Redux解读
tip01 概念&原理
Redux类似Vue中的Vuex, 在复杂的应用中改变react.js更新数据的方式,并实现统一数据管理的方式。应用较简单时真的不需要使用Redux, 考虑整个团队的技术水平以及熟悉的技术栈,适合自己的才是最好的!
使用Redux管理状态,流程的简单描述(摘自 https://www.redux.org.cn/):应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中。 惟一改变 state 的办法是触发 action,一个描述发生什么的对象。 为了描述 action 如何改变 state 树,你需要编写 reducers。我的理解是:通过dispatch传入action信号(“吃啥” “喝啥” “怎么买”)然后触发reducer("自己买" 还是 “外卖”,还是“DIY”), 熟悉Vuex的同学也可以看作是Vuex中的 mapMutations或者mapActions的作用, 而这一切的操作,专业点说是api或者方法的提供者便是 store , 他来自于火星 createStore, 名叫redux的火星 import { createStore } from 'redux'; const store = createStore(fn);
tip02 深入源码看原理
createStore到底是一个什么?“哎呀就是一个函数了 ,接受三个参数,分别是 reducer, preloadedState, enhancer”, 好不耐烦的样子,就像产品经理和你讲这个改下交互方式吧,为什么,“嗯。。。。嗯。。客户需求吧”, 好的,滚!!!!一个不能说服前端的产品不是一个好UI。
源码解析:
1 export default function createStore(reducer, preloadedState, enhancer) { 2 if ( 3 (typeof preloadedState === 'function' && typeof enhancer === 'function') || 4 (typeof enhancer === 'function' && typeof arguments[3] === 'function') 5 ) { 6 throw new Error( 7 'It looks like you are passing several store enhancers to ' + 8 'createStore(). This is not supported. Instead, compose them ' + 9 'together to a single function.' 10 ) 11 } 12 ......
createStore的三个参数,其中最常用的是第一个 reducer, 职责:数据加工(通过dispatch根据不同的action指示,执行不同的reducer,产生不同的数据)
preloadedState, 职责:数据的预渲染,可以看作初始化数据
enhancer, 职责:拓展功能的函数
createStore的返回值:
getState: 源码片段
1 function getState() { 2 if (isDispatching) { 3 throw new Error( 4 'You may not call store.getState() while the reducer is executing. ' + 5 'The reducer has already received the state as an argument. ' + 6 'Pass it down from the top reducer instead of reading it from the store.' 7 ) 8 } 9 10 return currentState 11 }
其作用就是返回一个state(redux管理下的数据),确切说是当前store中的state tree,其中 isDispatching是一个判断值:判断dispatch是否在执行,因为redux中为了保证数据更新的顺序性,杜绝bug,在数据处理期间不能获取数据。
1 function subscribe(listener) { 2 if (typeof listener !== 'function') { 3 throw new Error('Expected the listener to be a function.') 4 } 5 6 if (isDispatching) { 7 throw new Error( 8 'You may not call store.subscribe() while the reducer is executing. ' + 9 'If you would like to be notified after the store has been updated, subscribe from a ' + 10 'component and invoke store.getState() in the callback to access the latest state. ' + 11 'See https://redux.js.org/api-reference/store#subscribelistener for more details.' 12 ) 13 } 14 15 let isSubscribed = true 16 17 ensureCanMutateNextListeners() 18 nextListeners.push(listener) 19 20 return function unsubscribe() { 21 if (!isSubscribed) { 22 return 23 } 24 25 if (isDispatching) { 26 throw new Error( 27 'You may not unsubscribe from a store listener while the reducer is executing. ' + 28 'See https://redux.js.org/api-reference/store#subscribelistener for more details.' 29 ) 30 } 31 32 isSubscribed = false 33 34 ensureCanMutateNextListeners() 35 const index = nextListeners.indexOf(listener) 36 nextListeners.splice(index, 1) 37 currentListeners = null 38 } 39 }
这个方法主要任务是:当一个dispatch出发了action之后,进行一次监听,根据新的state更新视图,然后释放。
其中 ensureCanMutateNextListeners 方法是确保下次的监听队列是最新的,最齐全的队列,实质是把当前的队列浅拷贝给了下次的队列,源码如下:注意slice的用法
function ensureCanMutateNextListeners() { if (nextListeners === currentListeners) { nextListeners = currentListeners.slice() } }
接着 nextListeners.push(listener) ,添加新的监听,在 subscribe 最后,返回一个 unsubscribe 方法 :释放监听对象,清空整个队列。
重中之重的 dispatch 源码片段:
1 function dispatch(action) { 2 if (!isPlainObject(action)) { 3 throw new Error( 4 'Actions must be plain objects. ' + 5 'Use custom middleware for async actions.' 6 ) 7 } 8 9 if (typeof action.type === 'undefined') { 10 throw new Error( 11 'Actions may not have an undefined "type" property. ' + 12 'Have you misspelled a constant?' 13 ) 14 } 15 16 if (isDispatching) { 17 throw new Error('Reducers may not dispatch actions.') 18 } 19 20 try { 21 isDispatching = true 22 currentState = currentReducer(currentState, action) 23 } finally { 24 isDispatching = false 25 } 26 27 const listeners = (currentListeners = nextListeners) 28 for (let i = 0; i < listeners.length; i++) { 29 const listener = listeners[i] 30 listener() 31 } 32 33 return action 34 }
是不是看着很吓人,其实两句话的事,不,是一句话:根据不同的action执行不同的redreucer后遍历监听事件!完事!!!其实大概看过node Event原理的童鞋看这个并不难,本质就是事件执行后,通知队列池,依次执行池子里的监听事件,这里只不过是reducer后执行listener的,而currentReducer就是整个redux的数据处理中心,涵盖了所有reducer,根据不同的action指示进行数据处理,处理后的数据返回给 currentState。 dispatch方法只接受一个参数 action, 一个通过type作为标识的对象,具体用法参考官网 https://www.redux.org.cn/docs/basics/Actions.html ,这里只对原理源代码进行解释说明,明白原理,相信你才能更好的驾驭他。
下一篇解读第一个参数 reducer 以及 combineReducers!