redux源码浅析(2)

前言

在阅读源码的过程中我也翻阅了大量的资料。一般是先去看别人的源码分析完完整镇过的读一遍之后,看完了之后自己再把官网的clone下来自己再慢慢的阅读添加注释。希望大家在阅读完有感想之后也把官网源码clone下来不照着任何的资料边写注释边阅读完全部源码,这样子更有利于深刻理解。

在工作中其实会经常使用到 redux 数据状态处理库,在一开始的使用中就一直听到说 reducer 必须是一个纯函数,不能有副作用!state 需要有一个默认值!等等的约束。当然也踩过含有副作用修改了 state 造成视图层不更新的 bug(state 嵌套过深的锅。。。) 一直停留在知其然不知其所以然的层次 想到彻底的掌握以及明白 redux 的原理的办法当然就是直接阅读源码啦 而且 redux 非常简洁才 2kb 而已= = 非常值得一读

最开始我们分析 createStore 函数的源码,接下来还有一个 api 我们会经常使用到就是 combineReducer,用于把多个分模块的子 reducer 生成一个总的 reducer

combineReducers 的基本使用

 1 //常用的三个api
 2 import { createStore, combineReducers, applyMiddleware } from "redux";
 3 
 4 import { userReducer } from "./user/reducer";
 5 import { todoReducer } from "./todo/reducer";
 6 //combineReducers用于合并多个子reducer生成一个总的reducer
 7 const reducers = combineReducers({
 8   userStore: userReducer,
 9  todoStore: todoReducer 10 });

 

明白了 combineReducers 的基本用法之后我们就可以深入源码啦

上源码,为了减小篇幅,我删减了很多没用的代码(包括一些错误边界处理,其实很多错误边界处理都很有意思),如果想看完整的redux代码注释的话可以点击这里

combineReducers

通过源码 我们可以看到 combineReducers 其实接受要合并的 reducer 对象 返回 combination 函数 其实 combination 还是一个 reducer dispatch(action)的时候 会依次调用子 reducer 计算出子 reducer 的 state 值再而合并成对象。

  • combineReducers 一开始会循环所有的子 reducer 筛选出可用的 reducer(state 不能为 underfined 子 reducer 在 redux 内部自定义 action 的时候必须返回默认值 state)并且生成真正可用的 finalReducers
  • dispatch(action)的时候 会循环所有的子 reducer 传入 action 依次生成新的子 state 值 之后浅比较之前的 state 和新生成的 state 如果浅比较不相同就把 hasChanged 赋值为 true 证明子 state 改变了自然而然总 state 也改变了
  • combination 在返回 state 值时会进行判断 判断当前的 hasChanged 是否为 true 是的话证明 state 发生了变化返回新的 state 不然 state 没有变化返回旧的 state 值
 1 export default function combineReducers(reducers) {
 2   //获取所有子reducers的key值
 3   const reducerKeys = Object.keys(reducers);
 4   //筛选后可用的reducers
 5   const finalReducers = {};
 6   for (let i = 0; i < reducerKeys.length; i++) {
 7     const key = reducerKeys[i];
 8     /*
 9     * 开发环境下下遍历所有子reducers的value值
10     * 如果value为undefined 抛出警告
11     * 即 combineReducers({a:aReducer,b:bReducer}) 中的aReducer 不能为underfined
12     * */
13     if (process.env.NODE_ENV !== "production") { 14 if (typeof reducers[key] === "undefined") { 15 warning(`No reducer provided for key "${key}"`); 16  } 17  } 18 19 //进行筛选 筛选出函数类型的reducer 20 if (typeof reducers[key] === "function") { 21 finalReducers[key] = reducers[key]; 22  } 23  } 24 const finalReducerKeys = Object.keys(finalReducers); 25 26  let shapeAssertionError; 27 try { 28 //assertReducerShape是一个错误处理函数判断子reducer在传入一个非预定好的action时 是否会返回默认的state 29  assertReducerShape(finalReducers); 30 } catch (e) { 31 shapeAssertionError = e; 32  } 33 34 return function combination(state = {}, action) { 35 //state是否改变 这里判断state是否改变是通过浅比较的 所以才要求每次返回的state都是一个全新的对象 36 let hasChanged = false; 37 //新的state值 这里的state是根rootReducer的state 38 const nextState = {}; 39 for (let i = 0; i < finalReducerKeys.length; i++) { 40 const key = finalReducerKeys[i]; 41 //根据key值获取相当应的子reducer 42 const reducer = finalReducers[key]; 43 //获取上一次当前key值所对应的state值 下面要进行浅比较 44 const previousStateForKey = state[key]; 45 //获取传入action之后新生成的state值 46 const nextStateForKey = reducer(previousStateForKey, action); 47 if (typeof nextStateForKey === "undefined") { 48 const errorMessage = getUndefinedStateErrorMessage(key, action); 49 throw new Error(errorMessage); 50  } 51 //循环执行reducer 把新的值进行存储 52 nextState[key] = nextStateForKey; 53 //浅比较 这里把旧的子reducer state值 与传入action之后生成的state值进行浅比较 判断state是否改变了 54 hasChanged = hasChanged || nextStateForKey !== previousStateForKey; 55  } 56 //根据判断赶回state 只要有一个子reducer hasChanged为true那么就重新返回新的nextState 所以这里揭示了为什么reducer必须是纯函数而且如果state改变了必须返回一个新的对象 57 //如果返回的是依然的state对象(有副作用的push,pop方法)如果state是对象 因为nextStateForKey !== previousStateForKey比较的是引用 那么 hasChanged认为是false没有发生改变 自然而然下面返回的state依然是旧的state 58 return hasChanged ? nextState : state; 59  }; 60 } 61 62 function assertReducerShape(reducers) { 63 Object.keys(reducers).forEach(key => { 64 //遍历reducer 65 const reducer = reducers[key]; 66 //先依次执行reducer 看是否有默认返回值state 其中ActionTypes.INIT为内部自定义的action 自然而然的执行到default 如果返回undefined 抛出错误 state要有默认值 67 const initialState = reducer(undefined, { type: ActionTypes.INIT }); 68 69 if (typeof initialState === "undefined") { 70 throw new Error( 71 `Reducer "${key}" returned undefined during initialization. ` + 72 `If the state passed to the reducer is undefined, you must ` + 73 `explicitly return the initial state. The initial state may ` + 74 `not be undefined. If you don't want to set a value for this reducer, ` + 75  `you can use null instead of undefined.` 76  ); 77  } 78  if ( 79  typeof reducer(undefined, { 80  type: ActionTypes.PROBE_UNKNOWN_ACTION() 81  }) === "undefined" 82  ) { 83  throw new Error( 84  `Reducer "${key}" returned undefined when probed with a random type. ` + 85 `Don't try to handle ${ 86  ActionTypes.INIT 87 } or other actions in "redux/*" ` + 88 `namespace. They are considered private. Instead, you must return the ` + 89 `current state for any unknown actions, unless it is undefined, ` + 90 `in which case you must return the initial state, regardless of the ` + 91 `action type. The initial state may not be undefined, but can be null.` 92  ); 93  } 94  }); 95 }

 

总结

combineReducers的返回值实质上就是一个reducer函数,这个返回的reducer函数会把action传入各个子reducer中获取子state然后进行合并。

转载于:https://www.cnblogs.com/carrotWu/p/9662077.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园的建设目标是通过数据整合、全面共享,实现校园内教学、科研、管理、服务流程的数字化、信息化、智能化和多媒体化,以提高资源利用率和管理效率,确保校园安全。 智慧校园的建设思路包括构建统一支撑平台、建立完善管理体系、大数据辅助决策和建设校园智慧环境。通过云架构的数据中心与智慧的学习、办公环境,实现日常教学活动、资源建设情况、学业水平情况的全面统计和分析,为决策提供辅助。此外,智慧校园还涵盖了多媒体教学、智慧录播、电子图书馆、VR教室等多种教学模式,以及校园网络、智慧班牌、校园广播等教务管理功能,旨在提升教学品质和管理水平。 智慧校园的详细方案设计进一步细化了教学、教务、安防和运维等多个方面的应用。例如,在智慧教学领域,通过多媒体教学、智慧录播、电子图书馆等技术,实现教学资源的共享和教学模式的创新。在智慧教务方面,校园网络、考场监控、智慧班牌等系统为校园管理提供了便捷和高效。智慧安防系统包括视频监控、一键报警、阳光厨房等,确保校园安全。智慧运维则通过综合管理平台、设备管理、能效管理和资产管理,实现校园设施的智能化管理。 智慧校园的优势和价值体现在个性化互动的智慧教学、协同高效的校园管理、无处不在的校园学习、全面感知的校园环境和轻松便捷的校园生活等方面。通过智慧校园的建设,可以促进教育资源的均衡化,提高教育质量和管理效率,同时保障校园安全和提升师生的学习体验。 总之,智慧校园解决方案通过整合现代信息技术,如云计算、大数据、物联网和人工智能,为教育行业带来了革命性的变革。它不仅提高了教育的质量和效率,还为师生创造了一个更加安全、便捷和富有智慧的学习与生活环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值