React系列 --- 简单模拟语法(一)
React系列 --- Jsx, 合成事件与Refs(二)
React系列 --- virtualdom diff算法实现分析(三)
React系列 --- 从Mixin到HOC再到HOOKS(四)
React系列 --- createElement, ReactElement与Component部分源码解析(五)
React系列 --- 从使用React了解Css的各类使用方案(六)
React系列 --- 从零构建状态管理及Redux源码解析(七)
React系列 --- 扩展状态管理功能及Redux源码解析(八)html
基本功能以后,咱们再回头看看createStore.ts里有什么关键代码实现功能的react
import $$observable from 'symbol-observable' import { Store, PreloadedState, StoreEnhancer, Dispatch, Observer, ExtendState } from './types/store' import { Action } from './types/actions' import { Reducer } from './types/reducers' import ActionTypes from './utils/actionTypes' import isPlainObject from './utils/isPlainObject'
头部引入了symbol-observable
作响应式数据,其他都是一些类型声明和工具函数git
/** * Creates a Redux store that holds the state tree. * The only way to change the data in the store is to call `dispatch()` on it. * * There should only be a single store in your app. To specify how different * parts of the state tree respond to actions, you may combine several reducers * into a single reducer function by using `combineReducers`. * * @param reducer A function that returns the next state tree, given * the current state tree and the action to handle. * * @param preloadedState The initial state. You may optionally specify it * to hydrate the state from the server in universal apps, or to restore a * previously serialized user session. * If you use `combineReducers` to produce the root reducer function, this must be * an object with the same shape as `combineReducers` keys. * * @param enhancer The store enhancer. You may optionally specify it * to enhance the store with third-party capabilities such as middleware, * time travel, persistence, etc. The only store enhancer that ships with Redux * is `applyMiddleware()`. * * @returns A Redux store that lets you read the state, dispatch actions * and subscribe to changes. */
函数注释来看有三个入参github
参数 | 描述 |
---|---|
reducer | 给与当前state和action返回新的state |
preloadedState | 初始化state,能够从服务器获取或者恢复之前用户序列化的缓存数据 |
enhancer | 能够指定例如中间件的第三方功能加强 |
返回的store可让你读取state, 触发actions,监听变化算法
-------------省略部分代码---------------- 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.' ) } if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState as StoreEnhancer<Ext, StateExt> preloadedState = undefined } if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } return enhancer(createStore)(reducer, preloadedState as PreloadedState< S >) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext } if (typeof reducer !== 'function') { throw new Error('Expected the reducer to be a function.') }
都是一些基本的判断和报错机制,也是咱们手写代码省略掉的一步,中间有关于enhancer部分的代码能够后面再讲express
let currentReducer = reducer let currentState = preloadedState as S let currentListeners: (() => void)[] | null = [] let nextListeners = currentListeners let isDispatching = false /** * This makes a shallow copy of currentListeners so we can use * nextListeners as a temporary list while dispatching. * * This prevents any bugs around consumers calling * subscribe/unsubscribe in the middle of a dispatch. */ function ensureCanMutateNextListeners() { if (nextListeners === currentListeners) { nextListeners = currentListeners.slice() } } /** * Reads the state tree managed by the store. * * @returns The current state tree of your application. */ function getState(): S { if (isDispatching) { throw new Error( 'You may not call store.getState() while the reducer is executing. ' + 'The reducer has already received the state as an argument. ' + 'Pass it down from the top reducer instead of reading it from the store.' ) } return currentState as S }
开头是基本的声明变量,相比较咱们多了一个nextListeners
和isDispatching
redux
前者是做为currentListeners
浅拷贝的临时变量给分发阶段使用的,这样能够避免在这过程当中会用subscribe/unsubscribe所致使的bugsegmentfault
后者是用来锁定状态,在dispatching的过程当中作对应逻辑api
/** * Adds a change listener. It will be called any time an action is dispatched, * and some part of the state tree may potentially have changed. You may then * call `getState()` to read the current state tree inside the callback. * * You may call `dispatch()` from a change listener, with the following * caveats: * * 1. The subscriptions are snapshotted just before every `dispatch()` call. * If you subscribe or unsubscribe while the listeners are being invoked, this * will not have any effect on the `dispatch()` that is currently in progress. * However, the next `dispatch()` call, whether nested or not, will use a more * recent snapshot of the subscription list. * * 2. The listener should not expect to see all state changes, as the state * might have been updated multiple times during a nested `dispatch()` before * the listener is called. It is, however, guaranteed that all subscribers * registered before the `dispatch()` started will be called with the latest * state by the time it exits. * * @param listener A callback to be invoked on every dispatch. * @returns A function to remove this change listener. */ function subscribe(listener: () => void) { if (typeof listener !== 'function') { throw new Error('Expected the listener to be a function.') } if (isDispatching) { throw new Error( 'You may not call store.subscribe() while the reducer is executing. ' + 'If you would like to be notified after the store has been updated, subscribe from a ' + 'component and invoke store.getState() in the callback to access the latest state. ' + 'See https://redux.js.org/api-reference/store#subscribelistener for more details.' ) } let isSubscribed = true ensureCanMutateNextListeners() nextListeners.push(listener) return function unsubscribe() { if (!isSubscribed) { return } if (isDispatching) { throw new Error( 'You may not unsubscribe from a store listener while the reducer is executing. ' + 'See https://redux.js.org/api-reference/store#subscribelistener for more details.' ) } isSubscribed = false ensureCanMutateNextListeners() const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) currentListeners = null } }
比起咱们redux还作了几层机制数组
isDispatching
状态控制isSubscribed
控制移除事件状态/** * Dispatches an action. It is the only way to trigger a state change. * * The `reducer` function, used to create the store, will be called with the * current state tree and the given `action`. Its return value will * be considered the **next** state of the tree, and the change listeners * will be notified. * * The base implementation only supports plain object actions. If you want to * dispatch a Promise, an Observable, a thunk, or something else, you need to * wrap your store creating function into the corresponding middleware. For * example, see the documentation for the `redux-thunk` package. Even the * middleware will eventually dispatch plain object actions using this method. * * @param action A plain object representing “what changed”. It is * a good idea to keep actions serializable so you can record and replay user * sessions, or use the time travelling `redux-devtools`. An action must have * a `type` property which may not be `undefined`. It is a good idea to use * string constants for action types. * * @returns For convenience, the same action object you dispatched. * * Note that, if you use a custom middleware, it may wrap `dispatch()` to * return something else (for example, a Promise you can await). */ function dispatch(action: A) { if (!isPlainObject(action)) { throw new Error( 'Actions must be plain objects. ' + 'Use custom middleware for async actions.' ) } if (typeof action.type === 'undefined') { throw new Error( 'Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?' ) } if (isDispatching) { throw new Error('Reducers may not dispatch actions.') } 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
状态控制/** * Replaces the reducer currently used by the store to calculate the state. * * You might need this if your app implements code splitting and you want to * load some of the reducers dynamically. You might also need this if you * implement a hot reloading mechanism for Redux. * * @param nextReducer The reducer for the store to use instead. * @returns The same store instance with a new reducer in place. */ function replaceReducer<NewState, NewActions extends A>( nextReducer: Reducer<NewState, NewActions> ): Store<ExtendState<NewState, StateExt>, NewActions, StateExt, Ext> & Ext { if (typeof nextReducer !== 'function') { throw new Error('Expected the nextReducer to be a function.') } // TODO: do this more elegantly ;((currentReducer as unknown) as Reducer< NewState, NewActions >) = nextReducer // This action has a similiar effect to ActionTypes.INIT. // Any reducers that existed in both the new and old rootReducer // will receive the previous state. This effectively populates // the new state tree with any relevant data from the old one. dispatch({ type: ActionTypes.REPLACE } as A) // change the type of the store by casting it to the new store return (store as unknown) as Store< ExtendState<NewState, StateExt>, NewActions, StateExt, Ext > & Ext }
reducers的替代方法,通常场景比较少用到,基本代码很少
/** * Interoperability point for observable/reactive libraries. * @returns A minimal observable of state changes. * For more information, see the observable proposal: * https://github.com/tc39/proposal-observable */ function observable() { const outerSubscribe = subscribe return { /** * The minimal observable subscription method. * @param observer Any object that can be used as an observer. * The observer object should have a `next` method. * @returns An object with an `unsubscribe` method that can * be used to unsubscribe the observable from the store, and prevent further * emission of values from the observable. */ subscribe(observer: unknown) { if (typeof observer !== 'object' || observer === null) { throw new TypeError('Expected the observer to be an object.') } function observeState() { const observerAsObserver = observer as Observer<S> if (observerAsObserver.next) { observerAsObserver.next(getState()) } } observeState() const unsubscribe = outerSubscribe(observeState) return { unsubscribe } }, [$$observable]() { return this } } }
观察者模式的实现库作监听事件
// When a store is created, an "INIT" action is dispatched so that every // reducer returns their initial state. This effectively populates // the initial state tree. dispatch({ type: ActionTypes.INIT } as A) const store = ({ dispatch: dispatch as Dispatch<A>, subscribe, getState, replaceReducer, [$$observable]: observable } as unknown) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext return store
方法的最后会触发一个ActionTypes.INIT
的action作初始化数据,返回一个包含暴露的方法对象出去.
咱们再看看actionTypes.ts
源码作了什么
/** * These are private action types reserved by Redux. * For any unknown actions, you must return the current state. * If the current state is undefined, you must return the initial state. * Do not reference these action types directly in your code. */ const randomString = () => Math.random() .toString(36) .substring(7) .split('') .join('.') const ActionTypes = { INIT: `@@redux/INIT${randomString()}`, REPLACE: `@@redux/REPLACE${randomString()}`, PROBE_UNKNOWN_ACTION: () => `@@redux/PROBE_UNKNOWN_ACTION${randomString()}` } export default ActionTypes
不在于获得什么结果,只须要它是复杂难以跟开发定义的action重复就好了,为了执行一次distapch获取到初始的state.
学习完createStore.ts源码以后咱们能够将一些好的地方引入咱们的库里
nextListeners
充当临时变量传递给其余函数使用isDispatching
做为状态标记判断流程dispatch
函数增长容错机制,返回原样action
isSubscribed
控制监听事件解绑机制,从从新过滤赋值改为根据索引值移除事件action
执行预触发返回每一个reducer的初始数据function createStore (initStore = {}, reducer) { // 惟一数据源 let state = initStore // 监听队列 let listenList = [] // 监听队列浅拷贝 let nextListeners = listenList // 是否dispatch中 let isDispatching = false // 浅拷贝 function ensureCanMutateNextListeners () { if (nextListeners === listenList) { nextListeners = listenList.slice() } } // 惟一获取数据函数 function getState () { // 输出警告 if (isDispatching) { throw new Error( 'You may not call store.getState() while the reducer is executing. ' + 'The reducer has already received the state as an argument. ' + 'Pass it down from the top reducer instead of reading it from the store.' ) } return state } // 纯函数来执行修改,只返回最新数据 const dispatch = (action) => { // 严格控制dispatch,不得中途再次发送 if (isDispatching) { throw new Error('Reducers may not dispatch actions.') } // 增长意外防止操做 try { isDispatching = true state = reducer(state, action) } finally { isDispatching = false } // 获取更改后的数据同时获取最新队列 const listeners = (listenList = nextListeners) // 替换成原始遍历提升性能,遍历触发事件 for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } // 为了方便将action原样返回 return action } // 添加监听器, 同时返回解绑该事件的函数 const subscribe = (fn) => { if (isDispatching) { throw new Error( 'You may not call store.subscribe() while the reducer is executing. ' + 'If you would like to be notified after the store has been updated, subscribe from a ' + 'component and invoke store.getState() in the callback to access the latest state. ' ) } // 占位标记 let isSubscribed = true // 每次添加监听事件时浅拷贝最新队列 ensureCanMutateNextListeners() nextListeners.push(fn) return function unsubscribe () { if (!isSubscribed) { return } if (isDispatching) { throw new Error( 'You may not unsubscribe from a store listener while the reducer is executing. ' ) } isSubscribed = false // 每次移除监听事件时浅拷贝最新队列 ensureCanMutateNextListeners() // 根据索引值删除比filter过滤从新赋值效率高 const index = nextListeners.indexOf(fn) nextListeners.splice(index, 1) listenList = null } } // 默认触发一次dispatch以获取各个reduce的初始数据 dispatch({ type: `@@redux/INIT${Math.random() .toString(36) .substring(7) .split('') .join('.')}` }) return { getState, dispatch, subscribe } }
文章的完整代码能够直接查看demo6
createStore
函数还有一个入参enhancer
咱们以前没实现,
React提供使用中间件的惟一方式是applyMiddleware
函数,咱们看一下怎么介绍它的
Middleware 可让你包装 store 的 dispatch 方法来达到你想要的目的。同时, middleware 还拥有“可组合”这一关键特性。多个 middleware 能够被组合到一块儿使用,造成 middleware 链。其中,每一个 middleware 都不须要关心链中它先后的 middleware 的任何信息
import { createStore, applyMiddleware } from 'redux' import todos from './reducers' function logger({ getState }) { return (next) => (action) => { console.log('will dispatch', action) // 调用 middleware 链中下一个 middleware 的 dispatch。 let returnValue = next(action) console.log('state after dispatch', getState()) // 通常会是 action 自己,除非 // 后面的 middleware 修改了它。 return returnValue } } let store = createStore( todos, [ 'Use Redux' ], applyMiddleware(logger) ) store.dispatch({ type: 'ADD_TODO', text: 'Understand the middleware' }) // (将打印以下信息:) // will dispatch: { type: 'ADD_TODO', text: 'Understand the middleware' } // state after dispatch: [ 'Use Redux', 'Understand the middleware' ]
logger
是通用的中间件格式,这是一个三层嵌套函数,分别是{getState, dispatch}, next(实际上是下一个包装后的中间件)和action入参,其实至关于
function middleware ({getState, dispatch}) { return (next) => { return (action) => { // dosomething // 调用 middleware 链中下一个 middleware 的 dispatch。 let returnValue = next(action) // dosomething // 通常会是 action 自己,除非 // 后面的 middleware 修改了它。 return returnValue } } }
知道这个基本规则以后咱们就能够看看applyMiddleware
里面作了什么
咱们看一下先过一下源码里面作了些什么
import compose from './compose' import { Middleware, MiddlewareAPI } from './types/middleware' import { AnyAction } from './types/actions' import { StoreEnhancer, StoreCreator, Dispatch } from './types/store' import { Reducer } from './types/reducers' /** * Creates a store enhancer that applies middleware to the dispatch method * of the Redux store. This is handy for a variety of tasks, such as expressing * asynchronous actions in a concise manner, or logging every action payload. * * See `redux-thunk` package as an example of the Redux middleware. * * Because middleware is potentially asynchronous, this should be the first * store enhancer in the composition chain. * * Note that each middleware will be given the `dispatch` and `getState` functions * as named arguments. * * @param middlewares The middleware chain to be applied. * @returns A store enhancer applying the middleware. * * @template Ext Dispatch signature added by a middleware. * @template S The type of the state supported by a middleware. */
总的来讲就是建立一个应用程序的中间件去加强redux store的dispatch方法,对多种类的任务来讲很是便利,例如以简洁的方式表达异步流程或者输出每一个action payload的日志,而每一个中间件都会拿到dispatch
和getState
入参
-------------省略部分代码---------------- export default function applyMiddleware( ...middlewares: Middleware[] ): StoreEnhancer<any> { return (createStore: StoreCreator) => <S, A extends AnyAction>( reducer: Reducer<S, A>, ...args: any[] ) => { const store = createStore(reducer, ...args) let dispatch: Dispatch = () => { throw new Error( 'Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.' ) } const middlewareAPI: MiddlewareAPI = { getState: store.getState, dispatch: (action, ...args) => dispatch(action, ...args) } const chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose<typeof dispatch>(...chain)(store.dispatch) return { ...store, dispatch } } }
大体分析一下代码里作了什么操做
createStore
函数reducer
和其余入参store
dispatch
,抛出异常'不容许在构建中间件的时候dispatch,由于其余中间件不会被应用到该次dispatch'middlewareAPI
对象,暴露出对应的方法,目的是让每一个执行中间件都是同样的入参条件middlewareAPI
以后的新函数数组dispatch
函数为compose
以后的返回值store
实例的属性方法和包装后的新dispatch
方法上面有一个没解析的compose
函数,源码以下
/** * Composes single-argument functions from right to left. The rightmost * function can take multiple arguments as it provides the signature for the * resulting composite function. * * @param funcs The functions to compose. * @returns A function obtained by composing the argument functions from right * to left. For example, `compose(f, g, h)` is identical to doing * `(...args) => f(g(h(...args)))`. */ -------------省略部分代码---------------- export default function compose(...funcs: Function[]) { if (funcs.length === 0) { // infer the argument type so it is usable in inference down the line return <T>(arg: T) => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args: any) => a(b(...args))) }
总的来讲,除了类型判断,实际代码只有一个reduce
的应用...,这里能够知道每一个中间件是有顺序关系的,因此应用的时候须要注意一下.
applyMiddleware
的相关源码已通过了一遍,剩下咱们回顾一下在createStore
里是怎么处理相关逻辑的,放心,真的很少
-------------省略部分代码---------------- if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } return enhancer(createStore)(reducer, preloadedState as PreloadedState< S >) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext } -------------省略部分代码----------------
检查到传入enhancer
的时候直接中断流程,返回执行结果,
咱们再从新梳理一下流程:
调用方式
createStore(reducer, preloadedState, applyMiddleware(f1, f2, ...fn))
在createStore里若是检测到enhancer入参会
return enhancer(createStore)(reducer, preloadedState) 至关于 return applyMiddleware(f1, f2, ...fn)(createStore)(reducer, preloadedState)
在applyMiddleware源码可得知
// 初始化一个store let store = createStore(reducer, preloadedState); // 每一个中间件拿到的入参 const middlewareAPI: MiddlewareAPI = { getState: store.getState, dispatch: (action, ...args) => dispatch(action, ...args) } // 遍历的中间件大概流程这样子 middlewares = [ f1(middlewareAPI) => s1(next) => t1(...arg) f2(middlewareAPI) => s2(next) => t2(...arg) fn(middlewareAPI) => sn(next) => tn(...arg) ] // chain获得的数组就长这样子 const chain = [ s1(next) => t1(...arg) s2(next) => t2(...arg) sn(next) => tn(...arg) ] // compose通过reduce方法包装返回 const composeFn = s1((s2(sn(next) => tn(...arg))()) => t2(...arg))()) => t1(...arg) // 最终返回的dispatch方法 dispatch = (composeFn)(store.dispatch) // 总体流程 const applyMiddleware = (中间件数组) => (createStore) => (reducer, preloadedState) => {...store, dispatch: compose(...chain)(store.dispatch)}
这时候再回到中间件的通用代码能够知道
function middleware ({getState, dispatch}) { return (next) => { return (action) => { // dosomething // 调用 middleware 链中下一个 middleware 的 dispatch。 let returnValue = next(action) // dosomething // 通常会是 action 自己,除非 // 后面的 middleware 修改了它。 return returnValue } } }
阶段一: 接收相同的初始{getState, dispatch}
阶段二: 接收通过下一个中间件包装后的dispatch调用
阶段三: 接收action处理某些逻辑以后原样返回,通常不应修改action
效果: dispatch一个action,会用倒序的方式逐一通过每一个中间件的流程造成链式调用,而且先后通常不须要关心作些什么操做.
咱们既然已经知道了它的实现思路,接下来就能够简单封装一个了
function compose (...funcs) { if (funcs.length === 0) { // infer the argument type so it is usable in inference down the line return arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args))) }
// 接收中间件数组 function applyMiddleware (...middlewares) { // 接收createStore函数和reducer和其余参数 return (createStore) => (reducer, ...args) => { // 这就是原始的实例化store,因此applyMiddleware方法其实就是围绕在原始store的基础上添加功能 const store = createStore(reducer, ...args) // 先初始化dispatch方法占位,可是此时执行会抛出异常 let dispatch = () => { throw new Error( 'Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.' ) } /** * 构建中间件第一层运行的入参对象, 保证每一个中间件都是同样的参数条件,因此上面的抛出异常也是如此 * applyMiddleware([ f1(middlewareAPI) => s1(next) => t1(...arg) fn(middlewareAPI) => sn(next) => tn(...arg) * ]) * */ const middlewareAPI = { getState: store.getState, dispatch: (action, ...args) => dispatch(action, ...args) } // 遍历运行每一个中间件返回新的数组 // chain = [s1(next) => t1(...arg), ...sn(next) => tn(...arg)] const chain = middlewares.map((middleware) => middleware(middlewareAPI)) /* 返回加强功能后的dispatch方法 dispatch = (s1(sn(next) => tn(...arg))()) => t1(...arg))(store.dispatch) */ dispatch = compose(...chain)(store.dispatch) // 替代原始的store对象 return { ...store, dispatch } } }
由于新增了加强功能,因此咱们也要把createStore
修改一下,按照源码对应一下
由于参数里只有reducer
是必选,其余二者都是可选,因此咱们还要把入参顺序也替换一下
function createStore (reducer, initStore = {}, enhancer) { // 处理一下参数问题 if (typeof initStore === 'function' && typeof enhancer === 'undefined') { enhancer = initStore initStore = undefined } // 劫持enhancer if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } // 返回包装后的store return enhancer(createStore)(reducer, initStore) } -------------省略部分代码---------------- return { getState, dispatch, subscribe } }
最后只剩执行函数
// 初始数据 const initStore = { arNum: 0, mdNum: 1 } // 日志中间件 function logger ({ getState }) { return (next) => (action) => { console.log('will dispatch', action) // 调用 middleware 链中下一个 middleware 的 dispatch。 let returnValue = next(action) console.log('state after dispatch', getState()) // 通常会是 action 自己,除非 // 后面的 middleware 修改了它。 return returnValue } } // 实例化store let store = createStore(reducers, initStore, applyMiddleware(logger))
如今在index.html引入新的依赖执行能够发现也能正常输出日志了.
文章的完整代码能够直接查看demo7
其实上面就已经算是完成了一个简单的状态管理器了,可是咱们从Redux的API里其实可以看到还有一个方法是咱们还没了解过的,就大概说说
把一个 value 为不一样 action creator 的对象,转成拥有同名 key 的对象。同时使用 dispatch 对每一个 action creator 进行包装,以即可以直接调用它们。唯一会使用到 bindActionCreators 的场景是当你须要把 action creator 往下传到一个组件上,却不想让这个组件觉察到 Redux 的存在,并且不但愿把 dispatch 或 Redux store 传给它。
至于什么情景会遇到须要使用
你或许要问:为何不直接把 action creator 绑定到 store 实例上,就像传统的 Flux 那样?问题在于,这对于须要在服务端进行渲染的同构应用会有问题。多数状况下,你的每一个请求都须要一个独立的 store 实例,这样你能够为它们提供不一样的数据,可是在定义的时候绑定 action creator,你就只能使用一个惟一的 store 实例来对应全部请求了。
省略掉类型判断后的源码
import { Dispatch } from './types/store' import { AnyAction, ActionCreator, ActionCreatorsMapObject } from './types/actions' function bindActionCreator<A extends AnyAction = AnyAction>( actionCreator: ActionCreator<A>, dispatch: Dispatch ) { return function(this: any, ...args: any[]) { return dispatch(actionCreator.apply(this, args)) } } /** * Turns an object whose values are action creators, into an object with the * same keys, but with every function wrapped into a `dispatch` call so they * may be invoked directly. This is just a convenience method, as you can call * `store.dispatch(MyActionCreators.doSomething())` yourself just fine. * * For convenience, you can also pass an action creator as the first argument, * and get a dispatch wrapped function in return. * * @param actionCreators An object whose values are action * creator functions. One handy way to obtain it is to use ES6 `import * as` * syntax. You may also pass a single function. * * @param dispatch The `dispatch` function available on your Redux * store. * * @returns The object mimicking the original object, but with * every action creator wrapped into the `dispatch` call. If you passed a * function as `actionCreators`, the return value will also be a single * function. */ -------------省略部分代码---------------- export default function bindActionCreators( actionCreators: ActionCreator<any> | ActionCreatorsMapObject, dispatch: Dispatch ) { if (typeof actionCreators === 'function') { return bindActionCreator(actionCreators, dispatch) } if (typeof actionCreators !== 'object' || actionCreators === null) { throw new Error( `bindActionCreators expected an object or a function, instead received ${ actionCreators === null ? 'null' : typeof actionCreators }. ` + `Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?` ) } const boundActionCreators: ActionCreatorsMapObject = {} for (const key in actionCreators) { const actionCreator = actionCreators[key] if (typeof actionCreator === 'function') { boundActionCreators[key] = bindActionCreator(actionCreator, dispatch) } } return boundActionCreators }
bindActionCreator
返回绑定this指向的新函数
bindActionCreators
作了三件事:
actionCreators
是函数,直接返回调用bindActionCreator
actionCreators
非对象非null抛出异常actionCreators
是可迭代对象,返回遍历调用bindActionCreator
包装后的对象由于咱们的demo不须要用到,就不必实现了,你们知道原理便可