作为一个刚入门的码农来说,开始接触 redux 时那兴奋感,现在想想都令人振奋,好吧,初学者对于啥都感觉兴奋,计算机的世界总是那么给人神秘,令人神往,最后让人伤痕累累。不过那会儿是真的不容许自己把它扒光了看,再说,那会儿能把它扒掉几层皮啊,就算扒光了,凭我这捉急的智商,咱也看不懂哇。好吧,管它四八三十六干就得了,毕竟拿到工资才能买5毛钱的萝卜丝饼填肚子啊。是不是惨的不像话。这也算惨?实际情况是当我拿到那5毛钱工资时才发现,萝卜丝饼涨价了,萝卜丝饼涨价了,萝卜丝饼涨价了(重要的事情说三遍)...好吧,继续码代码吧,隔壁小卖部那一块钱一瓶的冰汽水仍然是我遥不可及的梦想...
虽然本人已经将近一年没有用 redux 了,但是还是觉得 redux 更适合自己,可能 redux 的 logo 比 mobx 的更炫酷吧
哈哈,玩笑玩笑...
话不多说,直接开始手撸 redux 源码。基于 v4.0.4 版本
源码解读
先来看下 redux 给我们提供了哪些 api
export {
createStore,
combineReducers,
bindActionCreators,
applyMiddleware,
compose,
__DO_NOT_USE__ActionTypes
}
接下来我们一一介绍
createStore
export default function createStore(reducer, preloadedState, enhancer) {
// 如果 preloadedState 和 enhancer 都为 function 的情况,抛错
// 必须符合 preloadedState 为 object, enhancer 为 function
if (
(typeof preloadedState === 'function' && typeof enhancer === 'function') ||
(typeof enhancer === 'function' && typeof arguments[3] === 'function')
) {
throw new Error(
'It looks like you are passing several store enhancers to ' +
'createStore(). This is not supported. Instead, compose them ' +
'together to a single function.'
)
}
// preloadedState 为 function,enhancer 为 undefined 的时候说明 initState 没有初始化, 但是有 middleware
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
// 如果 enhancer 存在
if (typeof enhancer !== 'undefined') {
// enhancer 不是 function,抛错
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
// 这段代码打动了我,但是目前我并不懂它内部的逻辑,到底是个什么神操作
// 好吧,现在先略过吧,只知道做了一些处理,我们先看下去,之后再解释
return enhancer(createStore)(reducer, preloadedState)
}
// 如果 reducer 不是 function,抛错
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.')
}
let currentReducer = reducer // 当前 reducer
let currentState = preloadedState // 当前 state
let currentListeners = [] // 取名为 listeners,又是数组,基本是个监听器
let nextListeners = currentListeners // 做浅拷贝
let isDispatching = false // 是否正在执行 dispatching
// 保存一份订阅的快照,我们可以在调度时将 nextListeners 用作临时列表。
// 可以防止使用者在调度过程中调用订阅/取消订阅的任何错误。
function ensureCanMutateNextListeners() {
// 判断 nextListeners 和 currentListeners 是不是同一个引用
if (nextListeners === currentListeners) {
// 如果是,转换引用地址(浅层深拷贝)
nextListeners = currentListeners.slice()
}
}
// 获取当前 state
function getState() {
// 阻止在 dispatching 过程中执行操作,否则抛错(因为要确保生成最新的 state)
if (isDispatching) {
// ...
}
// 为什么是最新的 state,参考 subscribe
return currentState
}
// 设置订阅器,一旦执行 dispatch 就会触发这个订阅器执行
// listener 是一个 callback
function subscribe(listener) {
// listener 必须是一个 function,否则抛错
if (typeof listener !== 'function') {
throw new Error('Expected the listener to be a function.')
}
// 同上
if (isDispatching) {
// ...
}
// 一个是否已订阅的标记,通过下面代码可以知道,其实就是是否有 listener
let isSubscribed = true
// 保存一份 nextListeners 的快照
ensureCanMutateNextListeners()
// 添加一个订阅函数
nextListeners.push(listener)
// 返回取消的 function,用于在组件卸载时移除订阅器
return function unsubscribe() {
// 用于确定是否有 listener
if (!isSubscribed) {
// 如果没有,直接返回
return
}
// 同上
if (isDispatching) {
// ...
}
// 是否已订阅标记为 false
isSubscribed = false
// 保存订阅快照
ensureCanMutateNextListeners()
// 找到当前监听器的位置
const index = nextListeners.indexOf(listener)
// 从 nextListeners 中删除(也就是说 subscribe 每次触发都会保存一份含有当前监听器的 nextListeners 列表,结束后被删除)
nextListeners.splice(index, 1)
}
}
// dispatch action
function dispatch(action) {
// action 必须是一个 object,否则抛错
if (!isPlainObject(action)) {
// ...
}
// action 必须有 type 属性,否则抛错
if (typeof action.type === 'undefined') {
// ...
}
// 同上
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
// dispatch 时标记 isDispatch 为 true,阻止同时执行其它任何操作
isDispatching = true
// 执行 reducer
// 这就是改变 store state 的唯一途径
currentState = currentReducer(currentState, action)
} finally {
// dispatch 过后,标记 isDispatching 为 false
isDispatching = false
}
// 这里拿到所有监听器
const listeners = (currentListeners = nextListeners)
// 执行每一个监听器
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
// 返回传入的 action
return action
}
// 这个方法其实在看 redux 源码前我根本不知道,官网好像也没有特别重点介绍么
// 看名字基本是替换更新 state 的 reducer
// redux 热加载机制的时候用到了
function replaceReducer(nextReducer) {
// 类型判断,不过多解释,reducer 必须是 function
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}
// 替换当前 reducer 为 nextReducer
currentReducer = nextReducer
// ActionTypes 的三个属性类似,只不过名称不同
// 这里应该就是执行 replaceReducer 这个方法时发送一个 dispatch,表明一下是 @@redux/REPLACE
dispatch({ type: ActionTypes.REPLACE })
}
// 应该是可变的?观察?
// 好吧,凭我这捉急的智商,还是不解释这里,感觉会被我带跑偏啊
// 希望有能之士帮忙解释下,在此先谢谢了
function observable() {
const outerSubscribe = subscribe
return {
subscribe(observer) {
if (typeof observer !== 'object' || observer === null) {
throw new TypeError('Expected the observer to be an object.')
}
function observeState() {
if (observer.next) {
observer.next(getState())
}
}
observeState()
const unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
[$$observable]() {
return this
}
}
}
// 当一个 redux store 被创建时,都会自动 dispatch 一个 "@@redux/INIT" 的 action
// 从而使 reducer 拥有初始 state 值
// 看到这里,感慨下,为啥我以前就没有想过 reducer 的初始值是怎么来的呢?
// 好吧,凭我这智商,就算想过这个问题,应该也想不到这么简单就能实现
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}
combineReducers
// 用于合并多个 reducer。一般用法:combineReducers({ a, b, c... })
export default function combineReducers(reducers) {
// 获取 reducers 中的所有 key
const reducerKeys = Object.keys(reducers)
// 最终 reducer's keys
const finalReducers = {}
// 遍历传入的 reducers 的所有 key
// 目的是过滤不符合规范的 reducer
for (let i = 0; i < reducerKeys.length; i++) {
// 获取每个 key
const key = reducerKeys[i]
// 除生产环境外,key 没有提供 reducer 都会给警告
if (process.env.NODE_ENV !== 'production') {
if (typeof reducers[key] === 'undefined') {
warning(`No reducer provided for key "${key}"`)
}
}
// 一切 ok 的情况下,给 finalReducers 赋值
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
// 获取所有符合规范的 reducer 的 key
const finalReducerKeys = Object.keys(finalReducers)
// 这用于确保我们不会多次警告相同的键,先往下看
let unexpectedKeyCache
if (process.env.NODE_ENV !== 'production') {
unexpectedKeyCache = {}
}
// reducer 断言
let shapeAssertionError
try {
// reducer 的标准规范:(previousState, action) => newState
// 规范 reducer,如果有不符合规范的 reducer,则抛错
assertReducerShape(finalReducers)
} catch (e) {
// 断言失败,赋值
shapeAssertionError = e
}
return function combination(state = {}, action) {
// reducers 断言失败的话,抛错
if (shapeAssertionError) {
throw shapeAssertionError
}
// 除生产环境外,都会有的规范
// 一些比较细致的规范,想要了解的同学晴自行查看,这里我就不过多解释了
if (process.env.NODE_ENV !== 'production') {
const warningMessage = getUnexpectedStateShapeWarningMessage(
state,
finalReducers,
action,
unexpectedKeyCache
)
if (warningMessage) {
warning(warningMessage)
}
}
let hasChanged = false
const nextState = {}
for (let i = 0; i < finalReducerKeys.length; i++) {
// 获取 finalReducers 的 key 和 value
const key = finalReducerKeys[i]
const reducer = finalReducers[key]
// 当前 key 的 state
const previousStateForKey = state[key]
// 执行 reducer,返回新的 state
const nextStateForKey = reducer(previousStateForKey, action)
// 如果没有返回新的 state,则抛错
if (typeof nextStateForKey === 'undefined') {
const errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
// 把新的 state 放入 nextState 对应的 key 里面
nextState[key] = nextStateForKey
// 判断新的 state 和 前一个 state 是不是同一个引用,以检验 reducer 是不是纯函数
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
}
}
bindActionCreators
// 返回一个注入 store dispatch 的 action creator 方法
function bindActionCreator(actionCreator, dispatch) {
return function() {
return dispatch(actionCreator.apply(this, arguments))
}
}
// 官网是这样介绍 bindActionCreators。大家可以仔细品味
// 把一个 value 为不同 action creator 的对象,转成拥有同名 key 的对象。同时使用 dispatch 对每个 action creator 进行包装,以便可以直接调用它们。
// 一般情况下你可以直接在 Store 实例上调用 dispatch。如果你在 React 中使用 Redux,react-redux 会提供 dispatch 函数让你直接调用它 。
// 惟一会使用到 bindActionCreators 的场景是当你需要把 action creator 往下传到一个组件上,却不想让这个组件觉察到 Redux 的存在,而且不希望把 dispatch 或 Redux store 传给它。
export default function bindActionCreators(actionCreators, dispatch) {
// 这里说明你也可以传入一个函数作为第一个参数,它会返回一个函数
if (typeof actionCreators === 'function') {
// 返回一个注入 store 的 dispatch 方法的 action creator
return bindActionCreator(actionCreators, dispatch)
}
// 类型检查,如果 actionCreators 不是一个对象,则抛错
if (typeof actionCreators !== 'object' || actionCreators === null) {
throw new Error(/** error */)
}
// 定义最终返回的 boundActionCreators
const boundActionCreators = {}
// 遍历 actionCreators
for (const key in actionCreators) {
// 获取当前 key 对应的 actionCreator
const actionCreator = actionCreators[key]
// 如果 actionCreator 是一个 function,则给 boundActionCreators 对应的 key 赋值一个注入 store 的 dispatch 方法的 action creator
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
// 返回给每个 action creator 绑定了 dispatch 方法的 boundActionCreators 对象
return boundActionCreators
}
compose
一个组合函数的函数,将函数串联起来从右到左执行
// 注意,因为compose的执行顺序原因,所以有的 middleware 插件会要求要放在最后面
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)))
}
applyMiddleware
// 添加中间件,看下官网介绍
// applyMiddleware(...middlewares)
// 每个 middleware 接受 Store 的 dispatch 和 getState 函数作为命名参数,并返回一个函数。
// 该函数会被传入 被称为 next 的下一个 middleware 的 dispatch 方法,并返回一个接收 action 的新函数,这个函数可以直接调用 next(action),或者在其他需要的时刻调用,甚至根本不去调用它。
// 调用链中最后一个 middleware 会接受真实的 store 的 dispatch 方法作为 next 参数,并借此结束调用链。
// 所以,middleware 的函数签名是 ({ getState, dispatch }) => next => action
export default function applyMiddleware(...middlewares) {
// 返回一个名为 createStore 的 function
// 还记得在 createStore.js 中的一段代码吗?
/**
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
// 这段代码打动了我,但是目前我并不懂它内部的逻辑,到底是个什么神操作
// 好吧,现在先略过吧,只知道做了一些处理,我们先看下去,之后再解释
return enhancer(createStore)(reducer, preloadedState)
}
*/
// 有 applyMiddleware 的时候直接先执行这里
// 到这里也就可以解释 enhancer(createStore)(reducer, preloadedState) 这段代码了
return createStore => (...args) => {
const store = createStore(...args)
// 定义一个 dispatch,调用会报错。
// 原因:dispatching 虽然构造middleware但不允许其他middleware应用
let dispatch = () => {
throw new Error(/** error */)
}
// 定义 middleware 中的 api
const middlewareAPI = {
// 注入 store 的 getState 方法
getState: store.getState,
// 调用每一个这样形式的 middleware = store => next => action =>{},
// 组成一个这样 [f(next)=>acticon=>next(action)...] 的 array,赋值给 chain
dispatch: (...args) => dispatch(...args)
}
const chain = middlewares.map(middleware => middleware(middlewareAPI))
// compose(...chain) 会形成一个调用链, next 指代下一个函数的注册, 这就是中间件的返回值要是 next(action) 的原因
// 如果执行到了最后 next 就是原生的 store.dispatch 方法
dispatch = compose(...chain)(store.dispatch)
// 返回增强的 store
return {
...store,
dispatch
}
}
}
写在最后
redux 确实非常感人啊,代码精简易懂,看完之后确实收获满满~~~