简介
JS 应用的状态容器,提供可预测的状态管理
三大原则
1、单一数据源
整个应用的全局 state 被存储在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中
2、state是只读的
唯一改变 state 的方法就是触发 action, action 是一个用于描述已发生事件的普通对象。
3、使用纯函数来执行修改
为了描述 action 如何改变 state tree,你需要编写纯的 reducers。
单向数据流
| 1
 | view -> dispath(action) -> reducer -> subscribe -> view(流回)
 | 
流程
同步
同步的 redux 可以非常清晰的体现出 3 大原则和单向数据流。
 
异步
redux 本身不提供处理异步的方式,如果你需要异步的操作需求,可以添加 middleware 来增强 redux 的功能。
 
核心
顶级API
1、createStore(reducer, [preloadedState], [enhancer])
创建store接收三个参数:
- reducer 是一个函数,返回新的状态,接受两个参数:当前的 state 和要触发的 action ;
- preloadedState 为初始时的 state 对象;
- enhancer 可选使用。用第三方第能力如中间件、时间旅行、持久化来增强 store;
2、combineReducers(reducers)
合并 reducer 单元,返回combination(state, action),即 reducer。
3、applyMiddleware(…middlewares)
   扩展中间件
| 12
 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
 
 | import compose from './compose'
 
 
 
 
 export default function applyMiddleware(...middlewares) {
 return (createStore) => (...args) => {
 const store = createStore(...args)
 let dispatch = () => {
 throw new Error(
 'Dispatching while constructing your middleware is not allowed. ' +
 'Other middleware would not be applied to this dispatch.'
 )
 }
 
 const middlewareAPI = {
 getState: store.getState,
 dispatch: (...args) => dispatch(...args),
 }
 
 const chain = middlewares.map((middleware) => middleware(middlewareAPI))
 
 dispatch = compose(...chain)(store.dispatch)
 
 return {
 ...store,
 dispatch,
 }
 }
 }
 
 | 
4、 bindActionCreators(actionCreators, dispatch)
  包装
5、compose(…functions)
   组合函数
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | export default function compose(...funcs) {if (funcs.length === 0) {
 return (arg) => arg
 }
 
 if (funcs.length === 1) {
 return funcs[0]
 }
 
 return funcs.reduce((a, b) => (...args) => a(b(...args)))
 }
 
 | 
Store API
- getState
- dispath
- subscribe
- replaceReducer
当 enhancer 传参的时候
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | if (typeof enhancer !== 'undefined') {if (typeof enhancer !== 'function') {
 throw new Error(
 `Expected the enhancer to be a function. Instead, received: '${kindOf(
 enhancer
 )}'`
 )
 }
 
 return enhancer(createStore)(reducer, preloadedState)
 }
 
 | 
getState
返回应用当前的 state 树
| 12
 3
 
 | function getState() {return currentState
 }
 
 | 
dispath
分发 action。这是触发 state 变化的惟一途径。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | function dispatch(action) {...
 try {
 isDispatching = true
 
 currentState = currentReducer(currentState, action)
 } finally {
 isDispatching = false
 }
 
 const listeners = (currentListeners = nextListeners)
 for (let i = 0; i < listeners.length; i++) {
 const listener = listeners[i]
 listener()
 }
 
 return action
 }
 
 | 
subscribe
添加一个变化监听器。每当 dispatch action 的时候就会执行,state 树中的一部分可能已经变化。你可以在回调函数里调用 getState() 来拿到当前 state。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | function subscribe(listener) {...
 
 var isSubscribed = true
 
 ensureCanMutateNextListeners()
 nextListeners.push(listener)
 
 return function unsubscribe() {
 if (!isSubscribed) {
 return
 }
 
 isSubscribed = false
 
 ensureCanMutateNextListeners()
 var index = nextListeners.indexOf(listener)
 nextListeners.splice(index, 1)
 }
 }
 
 | 
replaceReducer
替换 store 当前用来计算 state 的 reducer。
| 12
 3
 4
 5
 6
 7
 8
 
 | function replaceReducer(nextReducer) {if (typeof nextReducer !== 'function') {
 throw new Error('Expected the nextReducer to be a function.')
 }
 
 currentReducer = nextReducer
 dispatch({ type: ActionTypes.INIT })
 }
 
 | 
扩展
我们知道将 reducer 设计为纯函数,让它们更容易调试和比较;但这也带来了其它问题,比如涉及到接口调用之类的就不能处理。那么中间件便是用来增强 redux 功能的一种中间函数。
以 Redux-thunk 为例,以下为 thunk 的实现源码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | function createThunkMiddleware(extraArgument) {return ({ dispatch, getState }) =>
 next =>
 action => {
 if (typeof action === 'function') {
 return action(dispatch, getState, extraArgument);
 }
 
 return next(action);
 };
 }
 
 | 
生态库
- Redux Toolkit
- Redux-thunk
- React-redux
- React-redux-router
参考
Redux 中文官网