0%

Redux

1. Redux

Redux createStore三个主要的属性和方法是{store, getState, dispatch}。createStore是创建一个Redux Store, store是这个Redux Store的引用,getState是返回全局的State, dispatch是发送一个Action. 这个全局State对于JS来说是plain object,每次dispatch都会创建一个新的object,而redux-immutable会使用原来的Immutale Map引用。

其它一些辅助方法:
combineReducers(reducers), 这个是把reducersMap变成一个大reducer object.它接受一个Action和当前State, 然后遍历所有的reducer(这里可能会有性能问题,试想一千个reducer,会影响性能)。

  • createStore的第一个参数就是combineReducers(reducers)返回的结果, 内部创建一个currentState, finalReducers, dispatch方法。State的key就是reducers的key, 在createStore内部,store创建好之后会dispatch 当ActionTypes.INIT,这个会在finalReducers里面运行一次,由于这个时候全局State是undefined,所以会使用reducers的defaultState,这里也就解释为什么reducers的defaultState要和reducers的key(reducers的name)一样。

Action是一个Object,它包含type, payload(自定义的负荷). ActionTypes.INIT, 是Redux自带的Action,它的type其实是一个随机生成的字符串。我们不该针对这个ActionTypes.INIT写任何的reducer。

1
2
3
4
5
const ActionTypes = {
INIT: `@@redux/INIT${/* #__PURE__ */ randomString()}`,
REPLACE: `@@redux/REPLACE${/* #__PURE__ */ randomString()}`,
PROBE_UNKNOWN_ACTION: () => `@@redux/PROBE_UNKNOWN_ACTION${randomString()}`
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
return function combination(
// dispatch 当ActionTypes.INIT 的时候,state是undefined, 所以这里使用了函数默认值{}.
state: StateFromReducersMapObject<typeof reducers> = {},
action: AnyAction
) {


let hasChanged = false
const nextState: StateFromReducersMapObject<typeof reducers> = {}
// 遍历所有的Reducer
for (let i = 0; i < finalReducerKeys.length; i++) {
const key = finalReducerKeys[i]
// 获取一个reducer方法
const reducer = finalReducers[key]
// 获取当前的shape (某个reducer key下面的值)
const previousStateForKey = state[key]
// reduxer都会运行一次, 除非报错
// 当接受ActionTypes.INIT时,previousStateForKey是个undefined,所以reducer里面返回的是reducer的defaultState。
const nextStateForKey = reducer(previousStateForKey, action)

if (typeof nextStateForKey === 'undefined') {
const actionType = action && action.type
throw new Error()
}
// 改写下个shape (某个reducer key下面的值)
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
// 监测至少有一次变化
hasChanged =
hasChanged || finalReducerKeys.length !== Object.keys(state).length
return hasChanged ? nextState : state
}
  • createStore的第二个参数时initialState,它的值要和reducer的key一样。它会和Reducer产生的State做hydrate。

Redux中函数默认值的使用很广泛,第一重要的就是reducers中函数默认值defaultState的使用,然后是createStore中initialState的使用。createStore中初始化Reduxt的Gloabal State就是用到了上面两个函数默认值。

2. Middleware

Middleware是利用了职责链设计模式。所以适合compose方法,compose(a, b ,c ,d)变成a(b(c(d)))。关键其实就是传进去原来的store.dispatch方法, 传出一个新的dispatch方法。

3. Redux-Persist

这个库可以持久化Redux State,它有几个Action, 比如REHYDRATE。从字面意思理解就是当Redux创建了store,并且hydrate后,再来一次rehydrate。
我们知道hydrate其实就是ACTIONS.INIT触发finalReducers后得到一个state,这个state和createStore的第二个参数initialState hydrate后的值。那么Redux-Persist库必然也会得到一个state,这个state再次和之前的state hydrate。

Redux-Persist工作过程:

  • orginal crateStore结束, 得到一个origianl State
  • 从持久化storage里面读取item TODO: 不知道用什么规则读取
  • 把这个item hydarte之前的origianl State后得到一个新的 New State
  • 把这个New State作为最新的全局State
  • dispatch REHYDRATE,代表所有的恢复已经完成了

3.1 Redux-Persist-Immutable

使用了Redux-Perstit的transform,在每次保存或读取时做一次转化。保存时用transform从Immutable Map转为成字符串,读取时用transform从字符串转为Immutable Map.这字符串和plain object的字符串有点区别,它是一个带有类型描述的字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[
\"~#iM\",
[
\"generalSettings\",
[\"^0\",
[\"enableCustomerShortCut\",true]
],
\"printerGeneralSettings\",
[\"^0\",
[\"merchantHasPrinter\",false
]
],
\"printerTagsSettings\",
[\"~#iL\",[]],\"customerDisplaySettings\",[\"^0\",[]],
\"tableLayoutSettings\",
[\"^0\",[\"enableTableLayout\",false]]
]
]

4. Redux-Saga

这里要理解generate方法、yield的概念。

5. Reference:

  1. Redux 源码分析
  • 从核心模型出发提供overview,这里只需要有整体概念,不需要理解过多细节。
  • 从某个问题的提出与解决引导到模型的分模块。
  • 重复上面的过程,直到所有模块都涉及
  • 最后合并模块,理解它们的关系和如何接合,再次总结涉及理念。

所以源码讲解要通俗易懂,先要理解最核心概念和模型,这里不需要理解untils, 错误处理,默认值等等,只抓住核心概念。接下来理解各个主要模块的设计理念,然后过了一遍模块后,再理解它们是如何结合使用的。

  1. Redux源码解读之createStore