像素

redux 源码学习

createStore

createStore 基本结构

function createStore (
  reducer, // 跟 reducer
  preloadedState, // state 初始值
  enhancer // 增强器 用于增强stroe
) {
  ...省略

  // 当一个store被创建时,一个“INIT”动作被分派,这样每一个
  // Reducer返回它们的初始状态。这有效地填充了初始状态树。也相当于对currentState 初始化
  dispatch({ type: ActionTypes.INIT } as A)

  const store = {
    dispatch: dispatch as Dispatch<A>, // 触发stroe 中 state更新
    subscribe, // 订阅stroe 更新
    getState, // 获取 stroe 中 state
    replaceReducer, // 替换 reducer
    [$$observable]: observable // 兼容 rxjs 中的 Observable 
  } as unknown as Store<S, A, StateExt> & Ext
  return store
}

接收 初始根reducer、初始state、stroe 增强器,创建初始 stroe。

dispatch

调度action,也是触发 stroe 中 state 更新的唯一方法。

function dispatch(action: A) {
  // 判断 action 格式
  ...省略
  // 执行reducer
  try {
    isDispatching = true
    // 传入 state 与 action 到根reducer 执行结果更新 state
    currentState = currentReducer(currentState, action)
  } finally {
    isDispatching = false
  }

  // 触发所有的订阅
  // 监听会在 subscribe 中进行添加
  const listeners = (currentListeners = nextListeners)
  listeners.forEach(listener => {
    listener()
  })
  return action 
}

dispatch 接收的 action 必须是个普通对象,没有被修饰过的。

subscribe

function subscribe(listener: () => void) {
  ...省略
  // 1. 添加订阅
  let isSubscribed = true

  // 确保下次的订阅队列是新的
  ensureCanMutateNextListeners()
  // 生成一个监听器id,添加 nextListeners 事件队列中
  const listenerId = listenerIdCounter++
  nextListeners.set(listenerId, listener)

  // 2.返回一个取消订阅函数
  return function unsubscribe() {
    if (!isSubscribed) {
      return
    }
    ...省略
    isSubscribed = false

    ensureCanMutateNextListeners()
    nextListeners.delete(listenerId) //  nextListeners上操作清理订阅
    currentListeners = null // 清空current 队列
  }
}

subscribe 接收订阅函数,添加进订阅队列。返回一个清理订阅的方法。

getState

function getState(): S {
  if (isDispatching) {
    throw new Error(...)
  }
  return currentState as S
}

返回 stroe 当前 state

replaceReducer

function replaceReducer(nextReducer: Reducer<S, A>): void {
  if (typeof nextReducer !== 'function') {
    throw new Error(
      `Expected the nextReducer to be a function. Instead, received: '${kindOf(
        nextReducer
      )}`
    )
  }

  // 替换 Reducer
  currentReducer = nextReducer as unknown as Reducer<S, A, PreloadedState>

    // 替换时触发默认 action
    dispatch({ type: ActionTypes.REPLACE } as A)
}

接受一个新的 reducer 替换 当前 stroe 中的reducer,然后执行默认 action。

增强器 enhancer 的使用

function createStore (
  reducer, // 跟 reducer
  preloadedState, // state 初始值
  enhancer // 增强器 用于增强stroe
) {
  ...省略

  // 检验enhancers 增强器的类型 必须是函数
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error(
        `Expected the enhancer to be a function. Instead, received: '${kindOf(
          enhancer
        )}'`
      )
    }
    // 1.使用增强器 将 createStore 传递给 enhancer 得到增强过的 createStore
    // 2.然后再把接收的 reducer、preloadedState 传入,得到增强过的 stroe 返回。
    return enhancer(createStore)(
      reducer,
      preloadedState as PreloadedState | undefined
    )
  }

  ...省略

  const store = {
    ...略
  } as unknown as Store<S, A, StateExt> & Ext
  return store
}

enhancer 接收 createStore 然后返回被增强过的 createStore 方法。

combineReducers

将值为不同 reducer 函数的对象转换为单个 reducer 函数。调用每个子 reducer,并将它们的结果收集到一个 state 对象中,该对象的键与传递的reducer函数的键相对应。

export default function combineReducers(reducers: {
  [key: string]: Reducer<any, any, any>
}) {
  const reducerKeys = Object.keys(reducers) // 获取reducer key
  const finalReducers: { [key: string]: Reducer<any, any, any> } = {}
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i]

    if (typeof reducers[key] === 'function') { // 判断实际的reducer 必须为function
      finalReducers[key] = reducers[key] // 存放实际的reducer
    }
  }
  /**
   * @leran  1生成 reducer 的 key
   */
  const finalReducerKeys = Object.keys(finalReducers)

  try {
    assertReducerShape(finalReducers) // 2 判断所有的 reducer 的返回 是否有问题
  } catch (e) {
    shapeAssertionError = e
  }
    
  ...省略
  
  /**
   * 返回 结合reducer函数 作为根reducer 传入 createStore中
   */
  return function combination(
    state: StateFromReducersMapObject<typeof reducers> = {},
    action: Action
  ) {
    if (shapeAssertionError) {
      throw shapeAssertionError // 抛错
    }

    ...省略

    let hasChanged = false
    const nextState: StateFromReducersMapObject<typeof reducers> = {}
    // 遍历执行所有的子 reducer
    for (let i = 0; i < finalReducerKeys.length; i++) {
      const key = finalReducerKeys[i]
      const reducer = finalReducers[key] // 获取之前传入的 每个reducer
      const previousStateForKey = state[key] // 获取每个 reducer 之前的 state
      // 执行每个 reducer 获取返回的 state
      const nextStateForKey = reducer(previousStateForKey, action) // 触发reducer 获取对应 对应key reducer 更新后的 state

      // state 错误处理
      
      nextState[key] = nextStateForKey
      // 比较是否发生改变 state 只要有一个reducer 发生了改变
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    // 两次判断整体 state 是否改变
    hasChanged =
      hasChanged || finalReducerKeys.length !== Object.keys(state).length
    return hasChanged ? nextState : state // 如果有改变 返回新的 state
  }

}

通过传入 reducer 对象的 key,将子reducer返回的state 进行组合。返回 combination 作为根 reducer,遍历执行所有的子 reducer 判断是否更新。返回新的 state。

applyMiddleware

创建将中间件应用于Redux存储的分派方法的存储增强程序.

export default function applyMiddleware(
  ...middlewares: Middleware[]
): StoreEnhancer<any> {
  return createStore => (reducer, preloadedState) => {
    // 获取原 stroe
    const store = createStore(reducer, preloadedState)
    let dispatch: Dispatch = () => {
      throw new Error(
        'Dispatching while constructing your middleware is not allowed. ' +
        'Other middleware would not be applied to this dispatch.'
      )
    }
    // 传递给中间件参数 dispatch 在创建中间件的时候禁止使用
    const middlewareAPI: MiddlewareAPI = {
      getState: store.getState,
      dispatch: (action, ...args) => dispatch(action, ...args)
    }
    // 创建中间件使用链
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    // 通过 compose 依次使用中间件进行 dispatch 增强
    dispatch = compose<typeof dispatch>(...chain)(store.dispatch)

    return {
      ...store,
      dispatch // 覆盖了stroe 的 dispatch 也就是增强过的 dispatch
    }
  }
}

applyMiddleware 返回一个 enhancer 增强器,结合 createStroe中 enhancer 的使用 -- enhancer接收 createStroe 返回一个被增强的createStroe函数。先执行 createStroe 获取原 store, 然后对 store 的dispatch进行覆盖。

compose

从右到左组合单参数函数。

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))
  )
}

// 可以这样理解
compose([a,b,c])(arg);
a(b(c(arg)))

在applyMiddleware就有通过 compose 执行中间件增强 dispatch 结合 redux-thunk 源码看一下

function createThunkMiddleware<
  State = any,
  BasicAction extends Action = AnyAction,
  ExtraThunkArg = undefined
  >(extraArgument?: ExtraThunkArg) {
  // Standard Redux middleware definition pattern:
  // See: https://redux.js.org/tutorials/fundamentals/part-4-store#writing-custom-middleware
  const middleware: ThunkMiddleware<State, BasicAction, ExtraThunkArg> =
    ({ dispatch, getState }) =>
      next =>
        action => {
          if (typeof action === 'function') {
            return action(dispatch, getState, extraArgument)
          }
          return next(action)
        }
  return middleware
}

export const thunk = createThunkMiddleware()

thunk 首先在 applyMiddleware 中创建 chain 时调用传入 { dispatch, getState },返回中间件函数,中间件函数接收一个dispatch,然后返回一个dispatch函数。

next =>
  action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument)
    }
    return next(action)
  }
// 这里next就是前一个中间件返回的dispatch,可以看到会在 thunk 返回的 dispatch函数中进行调用

通过这种形式一层一层的对dispatch进行增强。thunk这里如果dispatch接收的action是函数类型的话,就会走自己的处理逻辑。