redux教程之源码解析createStore

Posted qdcnbj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redux教程之源码解析createStore相关的知识,希望对你有一定的参考价值。

redux源码
redux的源码很简单,分为以下几部分
  • createStore
  • combineReducers
  • applyMiddleware
  • compose
  • bindActionCreators
 
createStore即入口函数生成store,将reducer和middleware关联起来
combineReducers即将分散的reducer最终合并成一个统一的reducer
applyMiddleware即将多个中间件一次合并到reducer中,生成一个最终的reducer
compose是一个函数,从右到左来组合多个函数。将中间件数组依次从后向前。将后一个中间件包裹在前一个中间件函数中。
//示例代码
import { createStore } from ‘redux‘

function todos(state = [], action) {
  switch (action.type) {
    case ‘ADD_TODO‘:
      return state.concat([action.text])
    default:
      return state
  }
}

let store = createStore(todos, [‘Use Redux‘])

store.dispatch({
  type: ‘ADD_TODO‘,
  text: ‘Read the docs‘
})

console.log(store.getState())
// [ ‘Use Redux‘, ‘Read the docs‘ ]

 

createStore即入口函数:
export default function createStore(reducer, preloadedState, enhancer) {
   /** 入口参数判断*/
  if (
    (typeof preloadedState === ‘function‘ && typeof enhancer === ‘function‘) ||
    (typeof enhancer === ‘function‘ && typeof arguments[3] === ‘function‘)
  ) {
     /** enhancer即中间件,中间件需要合在一起传入createStore*/
    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可以省略*/
  if (typeof preloadedState === ‘function‘ && typeof enhancer === ‘undefined‘) {
    enhancer = preloadedState
    preloadedState = undefined
  }
/**middleware需要为函数 */
  if (typeof enhancer !== ‘undefined‘) {
    if (typeof enhancer !== ‘function‘) {
      throw new Error(‘Expected the enhancer to be a function.‘)
    }

    return enhancer(createStore)(reducer, preloadedState)
  }
/**即reducer需要为函数, */
  if (typeof reducer !== ‘function‘) {
    throw new Error(‘Expected the reducer to be a function.‘)
  }

  let currentReducer = reducer
  let currentState = preloadedState
  let currentListeners = []
  let nextListeners = currentListeners
  let isDispatching = false
/** 将新的监听函数和当前监听函数隔离开*/
  function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice()
    }
  }

  /**
   * Reads the state tree managed by the store.
   *
   * @returns {any} The current state tree of your application.
   */
  /**获取Store的currentState */
  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 currentState
  }

  /**绑定监听函数,即reducer执行完后后执行这些函数 */
  function subscribe(listener) {
    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#subscribe(listener) for more details.‘
      )
    }

    let isSubscribed = true
    /**新生成一个listener数组,以免push时影响 currentListener*/
    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#subscribe(listener) for more details.‘
        )
      }

      isSubscribed = false
      /**又出现了这个函数,确认是否可以变为下一个监听,z不知道这个函数有什么用 */
      ensureCanMutateNextListeners()
      /**确定解除绑定函数的位置并删除它 */
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }
  
  function dispatch(action) {
    /**判断action是否为纯对象 */
    if (!isPlainObject(action)) {
      throw new Error(
        ‘Actions must be plain objects. ‘ +
          ‘Use custom middleware for async actions.‘
      )
    }
    /**action必须有type */
    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 */
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
    /**执行完后通知listeners */
    const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }

  
  /**替换reducer,且初始化state */
  function replaceReducer(nextReducer) {
    if (typeof nextReducer !== ‘function‘) {
      throw new Error(‘Expected the nextReducer to be a function.‘)
    }

    currentReducer = nextReducer
    //初始化state
    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
      }
    }
  }

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

  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
}

 

以上是关于redux教程之源码解析createStore的主要内容,如果未能解决你的问题,请参考以下文章

精选博客|redux中间件机制—源码解析

6redux源码解析 - 中间件源码剖析

redux教程之源码解析2 combineReducers(分析在注释中)

Redux源码分析之compose

redux之createStore方法底层封装模拟

redux源码分析通过原生js手写实现redux来理解redux的数据响应