Redux 異步解析

Redux 同步操做

Redux 的基本用法以下所示:redux

在上面的流程中, 用戶經過 dispatch 發起 Action 後, reducer 會當即計算返回新的 state, 這是一個 同步 的過程。 可是若是咱們想在 Action 發起以後, 過一段時間再執行 reducer 計算 state, 即 異步計算 state, 該如何操做呢?

Redux 異步操做

Redux 中, Action對象 只是一個簡單的 js對象, 用於表達用戶想要修改 state 的意圖, Reducer 也是一個 js 純函數, 只負責 根據 Action 對象計算 state, 不會進行 API 請求和路由跳轉。那麼,咱們只能在發送 Action 的時候作些文章, 即對 dispatch 方法作改造, 使得 dispatch 方法能夠進行 異步操做bash

redux-thunk 是供 redux 使用的一個 中間件(middleware),這個中間件會對 store對象 原生的 dispatch 方法 進行包裝, 而後返回一個 新的dispatch方法。 咱們給這個 新的dispatch方法 傳入一個函數, 即 dispatch(func), 在這個函數中咱們執行 異步操做,而後在 異步操做的回調方法中執行 原生的dispatch(action) 操做, 修改 stateapp

import { createStore, applyMiddleware } from 'redux'
    import thunk from 'redux-thunk'
    
    // Action構造函數, 返回一個 Action 對象
    const Action = text => {
        value: text
    }
    
    // Action構建函數, 返回一個 thunk 函數
    const post = () => dispatch => {
        // 異步操做
        setTimeout(() =>{
            dispatch(Action('123'))
        }, 2000)
    }
    
    // reducer
    const reducer = (state, action) {
        ...
        return state;
    }
    
    // 中間件列表
    const middle = [thunk]
    
    // 構建 Store 對象, 並應用中間件
    const store = createStore(reducer, applyMiddleware(...middle))
    
    // 同步操做
    store.dispatch(Action('123'));
    
    // 異步操做
    store.dispatch(post())
    
複製代碼

Redux 異步解析

redux-thunk:異步

// redux 經過 applyMiddleware 使用 redux-thunk時, 會先執行 createThunkMiddleware 方法
    // 傳入 redux 原生的 dispatch、 getState 方法
    // 或者傳入上一個中間件包裝之後的 dispatch、getState
   function createThunkMiddleware(extraArgument) {
     return ({ dispatch, getState }) => next => action => {
       // 若是action是函數,即thunk函數, 直接執行thunk函數
       if (typeof action === 'function') {
         return action(dispatch, getState, extraArgument);
       }
  
       // 若是acton不是函數, 調用原生的dispatch方法派發Action, 修改state
       return next(action);
     };
   }
   
   const thunk = createThunkMiddleware();
   thunk.withExtraArgument = createThunkMiddleware;
   
   export default thunk
複製代碼

applyMiddleware:函數

export default function applyMiddleware(...middlewares) {
    
      // 返回enhancer, createStore => createStore
      return (createStore) => (reducer, preloadedState, enhancer) => {
      
        // 執行 redux 原生的 createStore 方法,構建一個 store 對象
        const store = createStore(reducer, preloadedState, enhancer)
        // 原生的 dispatch 方法
        let dispatch = store.dispatch
        let chain = []
    
        const middlewareAPI = {
          getState: store.getState,
          // 包裝之後的 dispatch 方法
          dispatch: (action) => dispatch(action)
        }
        
        // [chainA, chainB, chainC, chainD], 格式爲 next => action
        chain = middlewares.map(middleware => middleware(middlewareAPI))
        
        // 先經過 compose 方法處理 chain,結果爲 chainA(chainB(chainC(chainD(store.dispatch))))
        // dispatch 是包裝之後的dispatch方法
        dispatch = compose(...chain)(store.dispatch)
        
        // 返回一個新的Store對象, dispatch方法被從新包裝
        return {
          ...store,
          dispatch
        }
      }
    }
複製代碼

經過 applyMiddleware方法 和 thunk 中間件, store 對象的原生 dispatch 方法會被包裝成以下形式:post

// 包裝後的 dispatch 方法
    function (action) {
        if (typeof action === 'function') {
            return action(dispatch, getState, extraArgument);
        }
        return dispatch(action);
    }
    
複製代碼

store.dispatch(Action('123')), 咱們調用的是 包裝後的 dispatch方法, 由於 Action('123') 返回的是 對象即不是函數, 因此 新的dispatch方法 會直接 調用 store 原生的 dispatch 方法,而後 派發 Action觸發 state 的修改ui

store.dispatch(post()), 咱們調用的一樣是 包裝後的dispatch方法post() 返回的是 函數即 thunk 函數, 因此 thunk函數自動執行。在 thunk函數 中, 咱們能夠執行 異步操做, 而後在 異步操做回調方法 中調用 store 的原生 dispatch 方法派發 Action觸發 state 的修改spa

總結一下, Redux 的異步操做流程以下:3d

相關文章
相關標籤/搜索