理解|理解 redux
【理解|理解 redux】redux是当下流行的web前端所使用的一个状态管理架构。它本身是一个独立的构造,没有与任何其它库的耦合。由于reactjs的流行, 它自然而然的成为了react状态管理的延伸架构。 本文不打算讨论redux的优点以及细节, 只是想从纯粹的设计角度去理解redux状态管理的模式。
概览 redux把状态管理抽象成3个要素, action, reducer, store。
action是状态变化的描述性数据结构, 即一个标签(type)来标识action的名字, 和相关的数据
{
type: "添加订单",
text: "Eat meal"
}
reducer是action的handler, 是一个函数来具体执行状态变化操作.
store是状态对象和reducer的管理器, 在使用redux的时候, 你不应该直接执行reducer, 这破坏了它的设计意图。你要把它放到store中, 通过store去执行(dispatch)状态变化操作, 你也要通过store来获取状态对象。
更具体的描述:
- action, 描述发生了什么的对象, action是store的唯一信息来源, 通过store.dispatch(action)产生,
而dispatch就是去调用reducer更新状态, 在store内部, currentState维持应用程序的当前状态:
currentState = currentReducer(currentState, action)
一个action的结构:
{ type: "ADD_TODO", text: "Eat meal" }
- reducer, 完成action具体的操作: (oldState, action)=>newState, 也就是handling action.
写reducer时要求有初始化逻辑, 也就是如果state是undefined要给state赋值. 另外如果action未知时必须返回函数的state参数, 也就是旧的state.
function todos(state, action) { if (state === undefined) state = []; switch (action.type) { case .... default: return state; } }
- store负责把action和reducer结合起来, store 有以下特性:
- 获得状态 getState()
- 更新状态 dispatch(action)
- 登记监听器 subscribe(listener)
createStore(reducer, initialState)
注意initialState永远不用赋值, 所以总是undefined, 这正好被用在reducer函数参数中来做初始化
store = createStore(reducer)
在运行createStore时会初始化state, 也就是它内部做一次dispatch,
...
// 默认action
export var ActionTypes = {
INIT: '@@redux/INIT'
}
currentState = initialState // 默认是undefined,传给reducer做初始化
currentReducer = reducer
...
dispatch({ type: ActionTypes.INIT })
...
如果看dispatch函数, 他基本上就是去调用reducer,
currentState = currentReducer(currentState, action)
在初始化的dispatch时, action的值为
'@@redux/INIT'
, currentState为undefined
根据2的描述, 调用store=createStore(reducer)后, reducer返回的初始化状态对象被保存在store的currentState中, 通过store.getState()获取.
createStore建立后, store就成为调用reducer的代理, 通过store.getState()得到currentState, 通过store.dispatch(ACTION)再次调用reducer更新currentState.
总结 redux架构基于以下的约定构造:
- 函数reducer操作状态, 它的返回值构成了状态对象以及该对象的变化。但reducer不应该被直接调用, 状态对象被另一个独立的对象store(状态管理器)来维护. 在建立管理器时把reducer作为参数传递, 使得管理器可以调用它. 管理器通过暴露dispatch方法来调用reducer自身以改变状态, 同时状态对象(reducer的返回值)被封装在管理器中, 通过管理器暴露的方法getState获取.
- 状态信息被独立描述在action中, reducer的状态变化处理逻辑需要使用它. 它的结构包括变化类型(action.type), 以及变化的数据. reducer作为变化的具体处理者依据action的信息操作状态并返回新的状态
- reducer和action都由架构使用者定义和编码, redux提供的是管理器: 通过store=createStore(reducer)初始化状态对象, 通过store的其它方法来改变和获取状态. 而架构使用者只调用store方法来请求对状态的处理.
- 架构使用者在编码reducer时, 除了前述的约定以外, 还必须保证reducer是没有副作用的:
a. 不允许直接改变state的值,只允许生成新的值
b. 不应该有对外的API调用或者路由变化, 这些都应该在调用action前操作.
- 根(root) reducer,这个概念就是合并多个reducer, 形成一个单一的数据结构, 如:
reducers:
function visibilityFilter(state = VisibilityFilters.SHOW_ALL, action) { switch (action.type) { case ... default: return state } }function todos(state = [], action) { switch (action.type) { case ... default: return state } }
root reducer:
/ * 合并reducer其实就是合并数据结构,将reducer函数的返回值包装在一个结构里. 根reducer通过将其它reducer的调用返回值包装在一起, 形成一个完整的状态数据对象结构. */export default function todoApp(state = {}, action) { // 在store.dispatch时, 下面的reducer函数将依次被调用, // 当一个传递给reducer的action参数不在switch里时, default会直接返回state参数, 见前述reducer代码 return { vsfilter: visibilityFilter(state.vsfilter, action), tdlist: todos(state.tdlist, action) } }
最后, 应该传递给createStore的是这个根reducer:
store = createStore(todoApp)
推荐阅读
- 宽容谁
- 我要做大厨
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 叙述作文
- 深入理解Go之generate
- 20190302|20190302 复盘翻盘