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 下載代碼運行查看效果.
相關文章
相關標籤/搜索