分析redux源码
入口:index.ts(目录)重点标红
import createStore from './createStore' import combineReducers from './combineReducers' import bindActionCreators from './bindActionCreators' import applyMiddleware from './applyMiddleware' import compose from './compose' import warning from './utils/warning' import __DO_NOT_USE__ActionTypes from './utils/actionTypes' // types// store export {CombinedState, PreloadedState, Dispatch, Unsubscribe, Observable, Observer, Store, StoreCreator, StoreEnhancer, StoreEnhancerStoreCreator,ExtendState} from './types/store' // reducers export {Reducer,ReducerFromReducersMapObject,ReducersMapObject,StateFromReducersMapObject,ActionFromReducer,ActionFromReducersMapObject} from './types/reducers' // action creators export { ActionCreator, ActionCreatorsMapObject } from './types/actions' // middleware export { MiddlewareAPI, Middleware } from './types/middleware' // actions export { Action, AnyAction } from './types/actions' export { createStore,combineReducers,bindActionCreators,applyMiddleware,compose,__DO_NOT_USE__ActionTypes }
用法: const store = createStore( rootReducer, applyMiddleware(thunk));
createStore接收3个参数(reducer,preloadedState?,enhancer); 上面的applyMiddleware(trunk) 即 enhancer,
如果没有传preloadState参数则会这样:
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState as StoreEnhancer<Ext, StateExt>
preloadedState = undefined
}
没有enhancer的情况下,createStore会dispatch一个内部定义的action 来 初始化state,然后返回store
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
而有enhancer参数传入的情况下, enhancer被调用两次之后,也同样返回了store
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}
redux 设置了锁,来避免出现一些同步执行一些方法会导致的问题,如果一些情况同步执行,会报错,比如说同时更改和写入state的情况。
let isDispatching = false //加锁
//初始化state
let currentState = preloadedState as S //preloadState是参数
//获取state的函数:
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 }
let currentListeners: (() => void)[] | null = [] //初始化当前订阅者列表
let nextListeners = currentListeners //新订阅者列表
sunscribe方法:接受一个listener作为参数,产生一个新的listener列表,把新的Listener加入新列表里面,返回unsubscribe方法。
(我们会调用dispatch函数来更新state,而每次state更新时,会通知每个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)
function ensureCanMutateNextListeners() {
//判断是否指向同一个对象
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
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 } }
dispatch函数 (参数是action),调用reducer函数 更新state,并且通知所有最新的listener
let currentReducer = reducer //第一个参数reducer
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
//执行传入参数的reducer,返回新的state
currentState = currentReducer(currentState, action) } finally { isDispatching = false } //更新Listener列表,通知所有listener const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } return action }
其他:
replaceReducer //替换reducer
observable // observable版本的实现
2,applyMiddleware.ts
//记得createStore的参数enhancer吗?applyMiddleware(thunk)的返回值,一个函数,被执行了2次。
最终它返回了store,并且加了一个dispatch属性在上面(这个dispatch方法是经过包装过的,最里面才是原来的store.dispatch方法)
//定义参数部分略
export default function applyMiddleware( ...middlewares: Middleware[] ): StoreEnhancer<any> { return (createStore: StoreCreator) => <S, A extends AnyAction>( reducer: Reducer<S, A>, ...args: any[] //state ) => {
//初始化store,这里store会有一个dispatch的方法,这个dispatch会被传给middleware,经过一系列包装。
const store = createStore(reducer, ...args)
//变量dispatch 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)//把变量dispatch也传给了middlewares }
//执行了一次middlewares,传递参数。 const chain = middlewares.map(middleware => middleware(middlewareAPI))
//调用了compose2次,且最终返回新的dispatch方法,赋值给变量dispatch。 dispatch = compose<typeof dispatch>(...chain)(store.dispatch) //设定新的store.dispatch 并返回 store return { ...store, dispatch } } }
compose.ts
//参数定义略
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 //T是dispatch函数,dispatch = store.dispatch } if (funcs.length === 1) { return funcs[0] //只有一个,直接返回,然后被传入store.dispatch } //如果多个参数,多个dispatch合一(嵌套)
return funcs.reduce((a, b) => (...args: any) => a(b(...args)))
}
so.. middlewares
redux-trunk源码:
function createThunkMiddleware(extraArgument) {return
//trunk函数
({ dispatch, getState }) =>
//被传入middlewareAPI之后
next =>
//被传入store.dispatch之后,dipatch = action=>{return dispatch(action)}
action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument); } return next(action); }; } const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware; export default thunk;
用法: dispatch(actionCreater(params))
export function actionCreater(params){
//返回的dispatch函数
return (dispatch,getState)=>{ sendAsyncRequest(params).then((response)=>{ let action ={ type:'WHAT_EVER', payload:response }; return dispatch(action); }) } }
3.combineReducer.ts
用法: const rootReducer = combineReducers({
theDefaultReducer,
firstNamedReducer,
secondNamedReducer
});
作用,把reducers合成同一个
//定义类型略 //错误处理代码略
export default function combineReducers(reducers: ReducersMapObject) {
//获取key const reducerKeys = Object.keys(reducers) const finalReducers: ReducersMapObject = {} for (let i = 0; i < reducerKeys.length; i++) { const key = reducerKeys[i] if (process.env.NODE_ENV !== 'production') { if (typeof reducers[key] === 'undefined') { warning(`No reducer provided for key "${key}"`) } } if (typeof reducers[key] === 'function') {
//设定value finalReducers[key] = reducers[key] } } const finalReducerKeys = Object.keys(finalReducers) // This is used to make sure we don't warn about the same // keys multiple times. let unexpectedKeyCache: { [key: string]: true } if (process.env.NODE_ENV !== 'production') { unexpectedKeyCache = {} } let shapeAssertionError: Error try { assertReducerShape(finalReducers) } catch (e) { shapeAssertionError = e } //返回的combinedreducer return function combination( state: StateFromReducersMapObject<typeof reducers> = {}, action: AnyAction ) { 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: StateFromReducersMapObject<typeof reducers> = {}
//遍历来比较 for (let i = 0; i < finalReducerKeys.length; i++) { const key = finalReducerKeys[i] const reducer = finalReducers[key] const previousStateForKey = state[key]
//获取新的state const nextStateForKey = reducer(previousStateForKey, action) if (typeof nextStateForKey === 'undefined') { const errorMessage = getUndefinedStateErrorMessage(key, action) throw new Error(errorMessage) } nextState[key] = nextStateForKey
//判断state的值有没有改变 hasChanged = hasChanged || nextStateForKey !== previousStateForKey }
//判断key有没有改变 hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length
//如果有改变返回新state return hasChanged ? nextState : state } }
bindActionCreators
.ts
文档: 惟一会使用到 bindActionCreators
的场景是当你需要把 action creator 往下传到一个组件上,却不想让这个组件觉察到 Redux 的存在,而且不希望把 dispatch
或 Redux store 传给它。
把一个 value 为不同 action creator 的对象,转成拥有同名 key 的对象。同时使用 dispatch
对每个 action creator 进行包装,以便可以直接调用它们。
一般情况下你可以直接在 Store
实例上调用 dispatch
。如果你在 React 中使用 Redux,react-redux 会提供 dispatch
函数让你直接调用它 。
export default function bindActionCreators( actionCreators: ActionCreator<any> | ActionCreatorsMapObject, dispatch: Dispatch ) {
//function type 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"?` ) } //默认,如果是包含function的{} const boundActionCreators: ActionCreatorsMapObject = {} for (const key in actionCreators) { const actionCreator = actionCreators[key] if (typeof actionCreator === 'function') { boundActionCreators[key] = bindActionCreator(actionCreator, dispatch) } } return boundActionCreators }
function bindActionCreator<A extends AnyAction = AnyAction>( actionCreator: ActionCreator<A>, dispatch: Dispatch ) {
return function(this: any, ...args: any[]) {
return dispatch(actionCreator.apply(this, args))
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)