内容简介:redux 遵循严格的单向数据流,以React为例如下图:(网图,侵删)
redux 闲谈
redux 数据流程
redux 遵循严格的单向数据流,以React为例如下图:
(网图,侵删)
store.getState()
初始化
redux 的 Store
初始化通过 createStore
方法来进行初始化
const store = createStore(combineReducers, prevState, compose(applyMiddleware(...middleware)))
-
combineReducers
合并后的reducer,reducer 形式如下
function authReducer(state, action) { switch(action.type) { case 'login': return { ...state, isLogin: true } default: return {...state} } } function userReducer(state, action) { // ...如上 }
通过使用combineReducers({ authReducer, userReducer }) 返回一个reducers
prevState middleware
该部分初始化流程阶段,在下面applyMiddleware 会再次调用
combineReducers 合并 reducer
在上面说到我们可能存在多个reducer,也可能分模块来处理不同的状态问题,这里就需要合并不同模块的reducer, 实现代码 :
export default function combineReducers(reducers) { const reducerKeys = Object.keys(reducers) const finalReducers = {} for (let i = 0; i < reducerKeys.length; i++) { const key = reducerKeys[i] // 其他代码... if (typeof reducers[key] === 'function') { finalReducers[key] = reducers[key] // ① } } const finalReducerKeys = Object.keys(finalReducers) // 其他代码... return function combination(state = {}, action) { // ② // 其他代码... let hasChanged = false const nextState = {} for (let i = 0; i < finalReducerKeys.length; i++) { const key = finalReducerKeys[i] const reducer = finalReducers[key] const previousStateForKey = state[key] const nextStateForKey = reducer(previousStateForKey, action) // ③ if (typeof nextStateForKey === 'undefined') { const errorMessage = getUndefinedStateErrorMessage(key, action) throw new Error(errorMessage) } nextState[key] = nextStateForKey hasChanged = hasChanged || nextStateForKey !== previousStateForKey } return hasChanged ? nextState : state } }
传入一个reducers = { authReducer, userReducer }, 很明显对reducers 进行了对象遍历,在①这个位置进行了单个reducer函数的拷贝,在②这个位置redux 内部自己创建了一个reducer函数为 combination
, 在是③这个位置,进行了开发者定义的reducer定义,也就是说dispatch(action) -> combination(state, action) -> customReducer(state, action), 在循环内部每次获取对应的module 的state值作为 previousStateForKey
, 传入用户的reducer中,所以用户dispatch的 action中type是和reducer对应的位置在于用户自己的判断
compose 和 applyMiddleware
compose
compose 函数非常简短, 代码 如下:
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))) }
传入一个不定量函数作为参数,主要作为函数从一个数组形式例如[login, fetchToken, fetchUser]这样的函数传入,得到则是fetchUser(fetchToken(login(...args))) 这样的形式, 将函数组合起来,并从右到左,而且最右侧函数可以接受多个参数
示例仅仅为了说明,不在实际业务中出现
applyMiddleware
根据函数字面意思该函数为应用redux 中间件, 核心代码 如下:
export default function applyMiddleware(...middlewares) { return createStore => (...args) => { // 这里createStore 通过初始化时候传入 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 } } }
示例logger
const logger = store => next => action => { // example-① console.log('dispatching', action) let result = next(action) console.log('next state', store.getState()) return result } // usage: applyMiddleware(logger)
这里applyMiddleware 接受不定量的redux中间件,我们就来解释一下 example-①
这里申明是哪里来的。
在 applyMiddleware
源码中,传入middlewares后,在 ① 的位置就行了第一个次的中间件调用传入middlewareAPI,分别为 getState
和 dispatch
两个方法这里对应 example-①
中的 store,在 ② 的位置进行了上文说的 compose
调用,把所有的中间件进行了组合,从右到左的调用,此刻传入dispatch 方法,这里方法对应 example-①
中的 next
,在上文中说到 compose
对 函数进行了组合,我们这里将store.dispatch 传入当成参数,返回一个新的函数等价于我们在ViewUI 中dispatch的时候其实使用的 compose(...chain)(store.dispatch)(action)
这样的方式,所以在 example-①
中action 是开发者的action。使用中间件后的store.dispatch也是通过中间件包装后的dispatch。在最后 applyMiddleware
把dispatch 返回。
其他参考: redux applyMiddleware 解析
dispatch(action)
下面说到dispatch,这是我们经常用的,如下 代码 :
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 }
这里先说一下 isDispatching
作用, isDispatching 执行reducer 判断
这里这个参数 解决情况 如下:
var store = createStore((state={}, action) => { if (something) { store.dispatch({type: 'ANOTHER_ACTION'}) } return state })
继续下面来说在 ① 的位置执行 currentReducer, 这里reducer 为我们通过 createStore
传入combineReducers, 把对应的currentState 和 action传入, currentState 也是在初始阶段传入的 preloadState。在 ② 的位置则进行触发监听器, 监听器设置则在 store.subscribe
中增加。
现在来解释,action 和 reducer 对应关系
我当时回答的是: action.type 对应 reducer 的函数名称,如果一致的话就会执行。呵呵,那个涂鸦大工程师有问题了如何绑定的呢,怎么确定是reducerA 而不是B。 呵呵呵呵呵 。NB
后续
还问我 redux-saga、redux-thunk 异步处理方案,我提了一下redux-thunk,后续继续更新。
PS:真应该提升整个沟通流程质量
1.参考地址: https://redux.js.org
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
WWW信息体系结构(影印版第2版)
Louis Rosenfeld / 清华大学出版社 / 2003-6 / 49.8
如今的网站和内联网已经变得比以前越来越大,越来越有价值,而且越来越复杂,同时其用户也变得更忙,也更加不能容忍错误的发生。数目庞大的信息、快速的变化、新兴的技术和公司策略是设计师、信息体系结构构建师和网站管理员必须面对的事情,而这些已经让某些网让看起来像是个快速增长却规划很差的城市——到处都是路,却无法导航。规划精良的信息体系结构当前正是最关键性的。 本书介绍的是如何使用美学和机械学的理念创建......一起来看看 《WWW信息体系结构(影印版第2版)》 这本书的介绍吧!
RGB CMYK 转换工具
RGB CMYK 互转工具
HEX HSV 转换工具
HEX HSV 互换工具