Redux源码

206 阅读4分钟

Redux源码

redux基础教程

redux源码浅谈

createStore

creatStore函数接受三个参数reducer, preloadedState, enhancer最后返回一下API

export default function createStore(reducer, preloadedState, enhancer) {
// reducer 接受当前状态树并处理action返回新的状态树
// preloadedState 初始化state
// enhancer 增强store的功能,返回一个可以创建更加强大的store的函数

  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    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)
  }

  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
  }

  let currentReducer = reducer // 就是reducer
  let currentState = preloadedState // 就是传入的初始state
  let currentListeners = [] // 当前的监听器队列
  let nextListeners = currentListeners // 未来的监听器队列
  let isDispatching = false //  标志是否正在dispatch
  //确认能够修改未来监听队列判断当前的监听器队列和未来的是否一样,如果不一样那就将当前的赋值给未来的,
  function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice()
    }
  }
  ...
  ...
  // 返回常用API
  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [?observable]: observable
  }
}

1. dispatch

分发 action。这是触发 state 变化的惟一途径。

function dispatch(action) {
  // action要求是一个普通对象,而一个简单对象就是指通过对象字面量和new Object()创建的对象,如果不是就报错。
  if (!isPlainObject(action)) {
    throw new Error(
      'Actions must be plain objects. ' +
      'Use custom middleware for async actions.'
    )
  }
  // reducer内部是根据action的type属性来switch-case,决定用什么逻辑来计算state的,所以type属性是必须的。
  if (typeof action.type === 'undefined') {
    throw new Error(
      'Actions may not have an undefined "type" property. ' +
      'Have you misspelled a constant?'
    )
  }
  // 判断是否已经在dispatch
  if (isDispatching) {
    throw new Error('Reducers may not dispatch actions.')
  }
  // 这里就是计算新的state,并赋值给currentState
  try {
    isDispatching = true
    currentState = currentReducer(currentState, action)
  } finally {
    isDispatching = false
  }

  // state更新了后,将注册的回调都触发一遍
  const listeners = currentListeners = nextListeners
  for (let i = 0; i < listeners.length; i++) {
    const listener = listeners[i]
    listener()
  }

  return action
}

2. subscribe

一个变化监听器,每当 dispatch action 的时候就会执行

  1. 订阅器(subscriptions) 在每次 dispatch() 调用之前都会保存一份快照。当你在正在调用监听器(listener)的时候订阅(subscribe)或者去掉订阅(unsubscribe),对当前的 dispatch() 不会有任何影响。但是对于下一次的 dispatch(),无论嵌套与否,都会使用订阅列表里最近的一次快照
  2. 订阅器不应该注意到所有 state 的变化,在订阅器被调用之前,往往由于嵌套的 dispatch() 导致 state 发生多次的改变。保证所有的监听器都注册在 dispatch() 启动之前,这样,在调用监听器的时候就会传入监听器所存在时间里最新的一次 state。
function subscribe(listener) {
  // listener是state变化时的回调,必须是个函数
  if (typeof listener !== 'function') {
    throw new Error('Expected listener to be a function.')
  }

  let isSubscribed = true
  // 其实这个函数就是判断当前的监听器队列和未来的是否一样,如果不一样那就将当前的赋值给未来的,
  ensureCanMutateNextListeners()
  // 将回调压进未来的监听器队列中
  nextListeners.push(listener)

  // 注册监听器后会返回一个取消监听的函数
  return function unsubscribe() {
    if (!isSubscribed) {
      return
    }

    isSubscribed = false

    ensureCanMutateNextListeners()
    // 删除
    const index = nextListeners.indexOf(listener)
    nextListeners.splice(index, 1)
  }
}

3. getState

读取store管理的state树,返回应用的当前状态树

function getState() {
  return currentState
}

4. replaceReducer

替换 store 当前用来计算 state 的 reducer 这是一个高级 API。只有在你需要实现代码分隔,而且需要立即加载一些 reducer 的时候才可能会用到它。在实现 Redux 热加载机制的时候也可能会用到。

function replaceReducer(nextReducer) {
  if (typeof nextReducer !== 'function') {
    throw new Error('Expected the nextReducer to be a function.')
  }

  currentReducer = nextReducer
  dispatch({ type: ActionTypes.INIT })
}

compose

compose 可以接受一组函数参数,从右到左来组合多个函数,然后返回一个组合函数

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 利用 createStore 和 reducer 创建了一个 store,然后 store 的 getState 方法和 dispatch 方法又分别被直接和间接地赋值给 middlewareAPI 变量。

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    // 利用传入的createStore和reducer和创建一个store
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    // 让每个 middleware 带着 middlewareAPI 这个参数分别执行一遍
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    // dispatch = f1(f2(f3(store.dispatch))))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

combineReducers

将一个由多个不同 reducer 函数作为 value 的 object合并成一个最终的 reducer 函数,然后我们就可以对这个 reducer 调用 createStore 方法。并且合并后的 reducer 可以调用各个子 reducer,并把它们返回的结果合并成一个 state 对象。 由 combineReducers() 返回的 state 对象,会将传入的每个 reducer 返回的 state 按其传递给 combineReducers() 时对应的 key 进行命名。

export default function combineReducers(reducers) {
  const reducerKeys = Object.keys(reducers)
  // 有效的 reducer 列表
  const finalReducers = {}
  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') {
      finalReducers[key] = reducers[key]
    }
  }
  const finalReducerKeys = Object.keys(finalReducers)

  let unexpectedKeyCache
  if (process.env.NODE_ENV !== 'production') {
    unexpectedKeyCache = {}
  }

  let shapeAssertionError
  try {
    assertReducerShape(finalReducers)
  } catch (e) {
    shapeAssertionError = e
  }
  // 返回最终生成的 reducer
  return function combination(state = {}, action) {
    if (shapeAssertionError) {
      throw shapeAssertionError
    }

    if (process.env.NODE_ENV !== 'production') {
      const warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache)
      if (warningMessage) {
        warning(warningMessage)
      }
    }

    let hasChanged = false
    //定义新的nextState
    const nextState = {}
    for (let i = 0; i < finalReducerKeys.length; i++) {
      // 遍历reducers对象中的有效key,
      // 执行该key对应的value函数,即子reducer函数,并得到对应的state对象
      // 将新的子state挂到新的nextState对象上,而key不变
      const key = finalReducerKeys[i]
      const reducer = finalReducers[key]
      const previousStateForKey = state[key]
      const nextStateForKey = reducer(previousStateForKey, action)
      if (typeof nextStateForKey === 'undefined') {
        const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      nextState[key] = nextStateForKey
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    // 遍历一遍看是否发生改变,发生改变了返回新的state,否则返回原先的state
    return hasChanged ? nextState : state
  }
}

bindActionCreators

bindActionCreators可以把一个 value 为不同 action creator 的对象,转成拥有同名 key 的对象。同时使用 dispatch 对每个 action creator 进行包装,以便可以直接调用它们。

function bindActionCreator(actionCreator, dispatch) {
  return (...args) => dispatch(actionCreator(...args))
}
export default function bindActionCreators(actionCreators, dispatch) {
  // 如果actionCreators是一个函数,则说明只有一个actionCreator,就直接调用bindActionCreator
  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"?`
    )
  }
  // 遍历对象,然后对每个遍历项的 actionCreator 生成函数,将函数按照原来的 key 值放到一个对象中,最后返回这个对象
  const keys = Object.keys(actionCreators)
  const boundActionCreators = {}
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i]
    const actionCreator = actionCreators[key]
    if (typeof actionCreator === 'function') {
      boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
    }
  }
  return boundActionCreators
}

看源码更多的是去学习设计者的一种思想,以优化自己的代码