React-Redux 源码解析

createStore

通常而言,我查看一个库的源代码,首先回查看对应方法的参数,其次是对应的return ,而后再看代码的具体实现。git

经过查看源码,发现createStore 方法返回了一个对象, 该对象共暴露出了五个方法,四个经常使用的方法:github

return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
复制代码复制代码

查看源码的开始部分,咱们发现createStore能够传入两个三个参数:redux

export default function createStore(reducer, preloadedState, enhancer) 
复制代码复制代码

其中第一个参数reducer 是必需要传递的并且必须是一个函数,否则Redux回报一场数组

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

若是传递了第二个参数preloadedState,并且第二个参数不是一个function , 则将preloadedState 保存在内部变量currentState中, 也就是咱们给State 的默认状态bash

若是preloadedState 是一个function , 则将preloadedState 赋值给enhancerasync

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.')
    }
    // 运行enhancer, 通常enhancer 就是一组中间件
    return enhancer(createStore)(reducer, preloadedState)
  }

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

该方法中保存了三个重要的变量:函数

let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
复制代码复制代码
  1. currentReducer 保存了全部的Reducer
  2. currentState 将状态数据都保存在这里,也是Redux 操做数据的惟一对象
  3. currentListeners 会保存对Redux State 订阅的监听者

咱们已经知道了Redux能控制的如上三个主要内部变量了, 接下拉咱们会 根据createStore 暴露出来的五个方法,来学习怎么去操做这三个变量学习

return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
复制代码复制代码

dispatch(去掉验证代码)

function dispatch(action) {
      try {
      isDispatching = true
      // 调用Reduce 对action 进行处理,每次传入原始的state.返回更新后的states
      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
  }
复制代码复制代码

首先须要传递一个action 参数来告诉须要作的操做对象,action 只能是一个Object, 并且必须包含type 字段ui

if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      )
    }

    if (typeof action.type === 'undefined') { // 必须包含**Type**
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      )
    }
复制代码复制代码

咱们会调用内部变量currentReducer 去处理发起的对应的actionspa

currentState = currentReducer(currentState, action)
复制代码复制代码

咱们会发现currentReducer 实际上是一个function, 并且须要两个参数: currentState , action.

currentReducer 返回的值赋值给currentState, 由createStore 传入参数的分析得知,preloadedState 只能是要给Object, 因此currentReducer function 返回的是要给Object.

从这一行代码咱们能够总结获得:

reducer 其实就是一个函数,根据action 对 currentState 进行处理,而且返回新的currentState 的函数

const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }
复制代码复制代码

由上面一段代码咱们能够得知,在更新state , 须要去遍历执行全部的监听者(listener),让监听者得知state变动的信息

subscribe(订阅)

subscribe顾名思义就是消息订阅的意思

function subscribe(listener) {
    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)
    }
  }
复制代码复制代码

很简单的一段代码, 传入的参数listener 就是一个订阅者方法,

nextListeners.push(listener)
复制代码复制代码

将listener 保存在内部变量数组中。返回一个unsubscribe方法, 用来取消订阅

nextListeners.splice(index, 1) // 只要从数组中删除listener 就是取消订阅了
复制代码复制代码

getState(获取状态)

function getState() {
    return currentState
  }
复制代码复制代码

很是简单,就是返回内部变量currentState

replaceReducer(替换reducer)

function replaceReducer(nextReducer) {
    currentReducer = nextReducer
    dispatch({ type: ActionTypes.REPLACE })
  }

复制代码复制代码

就是替换当前的reducer.

总结

  1. 首先咱们须要调用createStore 方法建立一个store
let store = createStore(reducer, preloadedState)
复制代码复制代码

reducer 是一个function, 并且必需要 传递两个参数,第一个是state, 第二个是一个action

  1. 利用相关事件触发store.dispatch(action)去变动状态

这个action 必需要有type 属性

  1. 订阅状态变动store.subscribe(listener)
  2. 在listener中去获取最新state(store.getState()),而后作去相应的处理

能够在 Redux examples 下载代码运行查看效果.
相关文章
相关标签/搜索