redux是什么
redux是全局状态管理器,会将所有的状态都存在store中。
redux三大原则
- store: 单一数据源,全局只有一个store树
- action: state只读的,修改state的唯一方式,就是通过dispatch派发一个action动作
- reducer: 使用纯函数来修改,就收两个参数reducer(state,action),返回新的数据给store
工作流程
- 在页面的组件中,利用store的dispatch()方法,发送一个action
- redux接收到action后,分发给对应的reducer函数
- reducer处理完成后,返回新的state对象。这个state会更新到store对象里
- redux接收到新的store,通知store.subscribe()函数执行,进而驱动视图层作出对应的改变
state数据更改后,如何通知页面渲染
- 利用store.subscribe订阅一次redux的store,当下次store变化后,触发订阅函数执行checkForUpdates
- 通过store.getState()获取最新的state值,通过equalityFn函数比较newSelectedState和latestSelectedState,如果有变化就执行forceRender,触发react创建update对象,强制渲染;否则直接return
源码解读
- createStore(): createStore(reducer,preloadedState, enhancer)生成store对象
- combineReducers(): 将多个reducer合并起来。
- applyMiddleware(): applyMiddleware() 函数是一个增强器,组合多个中间件,最终增强store.dispatch函数,dispatch时,可以串联执行所有中间件。
- compose(): 用于把接收到的函数从右向左进行组合。
- bindActionCreators(): bindActionCreators(actionCreators, dispatch) 生成actions, 用于将传入的actionCreator与dispatch方法相结合,揉成一个新的方法
redux是如何工作的-createStore
const store = Redux.createStore(reducer,initState,applyMiddle)
作用:createStore创建一个store对象
参数:reducer处理函数 initState初始状态数据 指定中间件
再看store上的几个方法
- getState(): getState() 获取存在createStore函数内部闭包的对象。
- dispatch(): (派发),也就是把subscribe收集的函数,依次遍历执行
- subscribe(): (订阅),订阅收集函数存在数组中,等待触发dispatch依次执行。返回一个取消订阅的函数,可以取消订阅监听。
- replaceReducer(): replaceReducer(nextReducer) 主要用于redux开发者工具,对比当前和上一次操作的异同。有点类似时间穿梭功能。
从拿到入参到返回一个store过程
- 调用createStore
- 处理没有传入初始状态的情况
- 若enhancer不为空,则用enhancer包装createStore
- 定义内部变量currentReducer、currentState、currentListeners、nextListeners、isDispatching
- 定义ensureCanMutateNextListeners()改方法用于确保currentListeners与nextListeners不指向统一个引用
- 定义getState方法,用于获取当前的状态
- 定于subscribe,用于注册listeners,用于订阅监听函数
- 定义dispatch方法,用于派发action,调用reducer并触发订阅
- 定义replaceReducer方法,用于替换reducer
- 在replaceReducer中,执行一次dispatch,完成状态的初始化
- 定义observable,可忽略
redux是如何工作的-dispatch工作流程
- 调用dispatch,入参为action对象
- 前置校验。约束action中必须有type属性作为action的唯一标识
- 判断,如果当前已经位于dispatching流程中,则不允许再发起dispatch
- 执行reducer前先上锁,将isDispatching置为true。
- 调用reducer,计算新的state
- “解锁”,将dispatching置为false
- 触发订阅。 const listeners = (currentListeners = nextListeners);
- 返回action
注意:在调用 reducer 之前,Redux 首先会将 isDispatching 变量置为 true,待 reducer 执行完毕后,再将 isDispatching 变量置为 false。这里之所以要用 isDispatching 将 dispatch 的过程锁起来,目的是规避**“套娃式**”的 dispatch。
更准确地说,是为了避免开发者在 reducer 中手动调用 dispatch。 若真的在 reducer 中调用 dispatch,那么 dispatch 又会反过来调用 reducer,reducer 又会再次调用 dispatch......这样反复相互调用下去,就会进入死循环,属于非常严重的误操作(可理解为发布订阅的缺点)。
subscribe 是如何与 Redux 主流程结合的呢?
dispatch 中执行的 listeners 数组从订阅中来,而执行订阅需要调用subscribe。在实际的开发中,subscribe并不是一个严格必要的方法,只有在需要监听状态的变化时,我们才会调用 subscribe。
subscribe 在订阅时只需要传入监听函数,而不需要传入事件类型。这是因为 Redux 中已经默认了订阅的对象就是“状态的变化(准确地说是 dispatch 函数的调用)”这个事件。
首先,我们可以在 store 对象创建成功后,通过调用 store.subscribe 来注册监听函数,也可以通过调用 subscribe 的返回函数来解绑监听函数,监听函数是用 listeners 数组来维护的;当dispatch action 发生时,Redux 会在 reducer 执行完毕后,将 listeners 数组中的监听函数逐个执行。这就是 subscribe 与 Redux 主流程之间的关系