Redux,状态管理器,将state进行统一的管理,适用于复杂的用户操作、需要协同的用户操作、涉及到权限的网页、多数据源等场景。
基本概念
action:顾名思义,动作。需要执行怎样的操作,action是一个对象,内部包含了此action的类型和相关信息,规范的action如下:
{
type:"action_type",
payload:"message_with_action"
}
每次都写一遍action非常的蛋疼,所以可以自己设定一个function去生成固定的规范的action,这样一定程度上避免了拼写错误等操作
function createAction(text) {
return {
type: ADD_TODO,
text:"message_with_action"
}
}
store,存储数据(state)的地方,全局只能有一个store可以通过Redux提供的createStore来创建
import { createStore } from 'redux';
const store = createStore(reducer);
state,真正持有数据的对象,可以通过store.getState()
来得到
三大设计原则
- 单一数据源
整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。 - State 是只读的
惟一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。 - 纯函数
为了描述 action 如何改变 state tree ,你需要编写 reducers。
事物处理中心Reducer
Reducer应是一个纯函数,接收当前state和action,根据不同的action来返回一个新的state。
const chatReducer = (state = {}, action = {}) => {
const { type, payload } = action;
switch (type) {
case ADD_CHAT:
return Object.assign({}, state, {
chatLog: state.chatLog.concat(payload)
});
case CHANGE_STATUS:
return Object.assign({}, state, {
statusMessage: payload
});
case CHANGE_USERNAME:
return Object.assign({}, state, {
userName: payload
});
default: return state;
}
};
当存在非常多的action,如果无法对这些action进行区分,Reducer将会变得非常的庞大复杂难以阅读,因此Redux官方提供了一个方法combineReducers
让我们可以分开写不同的function来处理相似类型的action(action具体怎么分看,视情况而定),应用如下:
//state结构如下
{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true,
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}
//拆分后的Reducer
import { combineReducers, createStore } from 'redux'
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
case TOGGLE_TODO:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
})
}
return todo
})
default:
return state
}
}
function visibilityFilter(state = SHOW_ALL, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return action.filter
default:
return state
}
}
function todoApp(state = {}, action) {
return {
visibilityFilter: visibilityFilter(state.visibilityFilter, action),
todos: todos(state.todos, action)
}
}
//通过combineReducers重新组合
const todoApp = combineReducers({
visibilityFilter,
todos
})
export default todoApp
这种写法有一个前提,就是 State 的属性名必须与子 Reducer 同名。如果不同名,就要采用下面的写法。
const reducer = combineReducers({
a: doSomethingWithA,
b: processB,
c: c
})
//与上面的写法等价
function reducer(state = {}, action) {
return {
a: doSomethingWithA(state.a, action),
b: processB(state.b, action),
c: c(state.c, action)
}
}
总的来说,即将原本单个总的Reducer拆分成了:单个主Reducer、若干个子Reducer。主Reducer负责选择子Reducer并分发相应部分的state数据。子Reducer专注于处理state当中的一部分内容
存储器Store
store.getState
:获取最新的state,此函数将返回一个state;
store.dispatch
:分发action,在const store=creatStore(reducer)
的情况下会在执行dispatch后自动触reducer;
store.subscribe
:注册一个监听器,在stroe.dispatch()
后将以此执行监听器,此函数返回一个函数,调用返回的函数即可解除监听器
let unsubscribe = store.subscribe(() =>
console.log(store.getState())
);
unsubscribe();
Redux工作流程
- 用户触发操作激活
store.dispatch()
; - store函数调用reducer,并传入两个参数当前state与action;
- state发生变化触发listener;
- 如果listener内获取了最新的state并setState,将会进入React的更新流程;
可用的建议
- 将action定义为常量,并参照规范设计相应action;
/*
* action 类型
*/
export const ADD_TODO = 'ADD_TODO';
export const TOGGLE_TODO = 'TOGGLE_TODO'
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER'
参考:
1. 阮一峰Redux入门教程
2. Redux中文文档
3. action规范