文章目录
前言
前端开发库学习笔记,仅供参考交流,如有侵权,请联系删除。
Redux
1 简介
随着应用程序规模和范围的扩大,管理共享数据变得更加困难。Redux 被定义为 “JavaScript 应用的可预测状态容器”,它有助于确保你的应用能够可预测地运行,并且更容易测试。
2 笔记
创建一个Redux Store
Redux 是一个状态管理框架,可以与包括 React 在内的许多不同的 Web 技术一起使用。
在 Redux 中,有一个状态对象负责应用程序的整个状态, 这意味着如果你有一个包含十个组件且每个组件都有自己的本地状态的 React 项目,那么这个项目的整个状态将通过 Redux store 被定义为单个状态对象, 这是学习 Redux 时要理解的第一个重要原则:Redux store 是应用程序状态的唯一真实来源。
这也意味着,如果应用程序想要更新状态,只能通过 Redux store 执行。 单向数据流可以更轻松地对应用程序中的状态进行监测管理。
创建一个redux store
:
const reducer = (state = 5) => {
return state;
}
// 可从 Redux 对象获得 Redux 方法
// 例如:Redux.createStore()
// 在这里定义 store here:
const store = Redux.createStore(reducer)
从 Redux Store 获取状态
使用getState()
方法检索Redux store对象中保存的当前state。
const store = Redux.createStore(
(state = 5) => state
);
// 修改这行下面的代码
const currentState = store.getState();
分发 Action Event
dispatch 方法用于将 action 分派给 Redux store, 调用 store.dispatch(),并传递从一个 action creator 返回的值,将一个 action 送回给 store。
const store = Redux.createStore(
(state = {login: false}) => state
);
const loginAction = () => {
return {
type: 'LOGIN'
}
};
// 在这里发送 action:
store.dispatch(loginAction());
在Store里处理Action
Redux 中的 Reducers 负责响应 action 然后进行状态的修改。 reducer
将 state
和 action
作为参数,并且它总是返回一个新的 state
,而不会直接修改状态。 我们要知道这是 reducer 的唯一的作用。 它不应有任何其他的作用:比如它不应调用 API 接口,也不应存在任何潜在的副作用。 reducer 只是一个接受状态和动作,然后返回新状态的纯函数。
const defaultState = {
login: false
};
const reducer = (state = defaultState, action) => {
// 修改这行下面的代码
if(action.type == 'LOGIN'){
const newState = {login:true}
return newState
}else{
return state
}
// 修改这行上面的代码
};
const store = Redux.createStore(reducer);
const loginAction = () => {
return {
type: 'LOGIN'
}
};
使用 Switch 语句处理多个 Actions
const defaultState = {
authenticated: false
};
const authReducer = (state = defaultState, action) => {
// 修改这行下面的代码
switch(action.type){
case 'LOGIN':
return {
authenticated: true
};
case 'LOGOUT':
return {
authenticated: false
};
default:
return state
}
// 修改这行上面的代码
};
const store = Redux.createStore(authReducer);
const loginUser = () => {
return {
type: 'LOGIN'
}
};
const logoutUser = () => {
return {
type: 'LOGOUT'
}
};
不要忘记在 switch 语句中写一个 default
case,返回当前的 state。 这是很重要的,因为当程序有多个 reducer,当每一个 action 被 dispatch 时它们都会运行,即使 action 与该 reducer 无关。 在这种情况下,你要确保返回当前的 state
。
使用 const 声明 Action Types
在使用Redux时的一个常见做法是将操作类型指定为只读,然后在任何使用它们的地方引用这些常量,通过将action types使用const
声明重构
你正在使用的代码。通常以全部大写形式写出常量,这也是Redux的标准做法。
const LOGIN = "LOGIN"
const LOGOUT = "LOGOUT"
const defaultState = {
authenticated: false
};
const authReducer = (state = defaultState, action) => {
switch (action.type) {
case LOGIN:
return {
authenticated: true
}
case LOGOUT:
return {
authenticated: false
}
default:
return state;
}
};
const store = Redux.createStore(authReducer);
const loginUser = () => {
return {
type: LOGIN
}
};
const logoutUser = () => {
return {
type: LOGOUT
}
};
注册Store监听器
在 Redux store
对象上访问数据的另一种方法是 store.subscribe()
。 这允许将监听器函数订阅到 store,只要 action 被 dispatch 就会调用它们。 这个方法的一个简单用途是为 store 订阅一个函数,它只是在每次收到一个 action 并且更新 store 时记录一条消息。
const ADD = 'ADD';
const reducer = (state = 0, action) => {
switch(action.type) {
case ADD:
return state + 1;
default:
return state;
}
};
const store = Redux.createStore(reducer);
// 全局 count 变量:
let count = 0;
// 修改这行下面的代码
store.subscribe(() => count++ );
// 修改这行上面的代码
store.dispatch({type: ADD});
console.log(count);
store.dispatch({type: ADD});
console.log(count);
store.dispatch({type: ADD});
console.log(count);
组合多个Reducers
为了将多个 reducer 组合在一起,Redux 提供了combineReducers()
方法。 该方法接受一个对象作为参数,在该参数中定义一个属性,该属性将键与特定 reducer 函数关联。 Redux 将使用给定的键值作为关联状态的名称。
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
const counterReducer = (state = 0, action) => {
switch(action.type) {
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
default:
return state;
}
};
const LOGIN = 'LOGIN';
const LOGOUT = 'LOGOUT';
const authReducer = (state = {authenticated: false}, action) => {
switch(action.type) {
case LOGIN:
return {
authenticated: true
}
case LOGOUT:
return {
authenticated: false
}
default:
return state;
}
};
const rootReducer = Redux.combineReducers({
count: counterReducer,
auth: authReducer
});
// 在这里定义 root reducer
const store = Redux.createStore(rootReducer);
发送Action Data给Store
在之前的练习中, action 并未包含除 type之外的任何信息。 还可以和 action 一起发送特定数据。 事实上,这是非常常见的,因为 action 通常源于一些用户交互,并且往往会携带一些数据, Redux store 经常需要知道这些数据。
const ADD_NOTE = 'ADD_NOTE';
const notesReducer = (state = 'Initial State', action) => {
switch(action.type) {
// 修改这行下面的代码
case ADD_NOTE:
return action.text;
// 修改这行上面的代码
default:
return state;
}
};
const addNoteText = (note) => {
// 修改这行下面的代码
return {
type:ADD_NOTE,
text:note
}
// 修改这行上面的代码
};
const store = Redux.createStore(notesReducer);
console.log(store.getState());
store.dispatch(addNoteText('Hello!'));
console.log(store.getState());
使用中间件处理异步操作
在某些时候,需要在 Redux 应用程序中使用异步请求,那么如何处理这些类型的请求? Redux 中间件专为此目的而设计,称为 Redux Thunk 中间件。
要使用Redux Thunk中间件,需要将其作为参数传递给Redux.applyMiddleware(),然后将此函数作为第二个可选参数提供给 createStore() 函数,如下面代码的最后一段。
const REQUESTING_DATA = 'REQUESTING_DATA'
const RECEIVED_DATA = 'RECEIVED_DATA'
const requestingData = () => { return {type: REQUESTING_DATA} }
const receivedData = (data) => { return {type: RECEIVED_DATA, users: data.users} }
//通常再执行异步行为之前 dispatch action,以便应用程序状态知道正在请求某些数据
//(例如,这个状态可以显示加载图标)。
//然后,一旦收到数据,就会发送另一个 action,
//该 action 的 data 是请求返回的数据同时也代表 API 操作完成。
const handleAsync = () => {
return function(dispatch) {
// 在这里发送 request action
dispatch(requestingData());
setTimeout(function() {
let data = {
users: ['Jeff', 'William', 'Alice']
}
// 在这里发送接收到的 data action
dispatch(receivedData(data));
}, 2500);
}
};
const defaultState = {
fetching: false,
users: []
};
const asyncDataReducer = (state = defaultState, action) => {
switch(action.type) {
case REQUESTING_DATA:
return {
fetching: true,
users: []
}
case RECEIVED_DATA:
return {
fetching: false,
users: action.users
}
default:
return state;
}
};
const store = Redux.createStore(
asyncDataReducer,
Redux.applyMiddleware(ReduxThunk.default)
);