Redux multiple dispatch,batch redux-thunk

Redux multiple dispatch,batch redux-thunk

November 30, 2019

·

5 min read

redux 核心更新 flow dispatch action => reducer => store,當你用 redux 運行多個 dispatch 時,每一個 dispatch 都會獨立更新下去的,這代表著你會 update component 多次,如果你的更新資料又彼此關聯,就可能會發生錯誤。

目前執行的專案,資料都是 linked list,若沒有注意好 dispatch 更新執行順序的話,時常會遇到問題。

  • 多個 dispatch 更新
function initINFO (){
  fetch(`API_URL/getCommentList`)
    .then(res => res.json)
    .then(data =>
      // if ADD_USERCOMMENT update component
      // and it depends userInfo data
      // component maybe happen error
      dispatch({type: ADD_USERCOMMENT, payload: data.list})
      if (data.userInfo) {
        dispatch({type: INIT_INFO, payload: data.userInfo})
      }
    )
    .catch(err => showError(err))
}

處理的做法就是直接封裝整個 dispatch,讓每個 dispatch 都先不要往下執行 update component。

redux batch

react redux v7 有提供 batch,讓我們能直接封裝多個 dispatch,這是依賴 react 的 unstable_batchedUpdate,讓 rerender 這件事情能夠被卡住,react 實現方法大致上就是用 shouldBatchUpdates 變數搭配 fiber schedule 來判斷更新,讓更新這件事變成同步,詳細可直接看下方 react unstable_batchedUpdates source code。

  • batch 使用方法
import { batch } from "react-redux";
function myThunk() {
  return (dispatch, getState) => {
    // should only result in one combined re-render, not two
    batch(() => {
      dispatch(increment());
      dispatch(increment());
    });
  };
}

react redux github batch Q&A

react unstable_batchedUpdates source code

redux thunk

redux thunk 同樣可以幫助我們處理多個 dispatch,但是與 batch 原理不大相同,redux thunk,是將 dispatch 往後延遲到最後一次執行。

乍聽之下可能覺得這有點魔幻,但我貼上 redux thunk 的介紹你一定會恍然大悟。redux thunk 就是將 dispatch 封裝起來在最後一次真正執行 store.dispatch,所以你就只會觸發一次的 redux store update,進而達到只 rerender 一次。

// calculation of 1 + 2 is immediate
// x === 3
let x = 1 + 2;

// calculation of 1 + 2 is delayed
// foo can be called later to perform the calculation
// foo is a thunk!
let foo = () => 1 + 2;
  • what is thunk
// calculation of 1 + 2 is immediate
// x === 3
let x = 1 + 2;

// calculation of 1 + 2 is delayed
// foo can be called later to perform the calculation
// foo is a thunk!
let foo = () => 1 + 2;
  • Add thunk on redux middleWare
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import reducers from "../redux/reducers";

const store = createStore(reducers, applyMiddleware(thunk));

function fetchUser(data) {
  return (dispatch, getState) => {
    dispatch({ type: ADD_USERCOMMENT, payload: data.list });
    if (data.userInfo) {
      dispatch({ type: INIT_INFO, payload: data.userInfo });
    }
  };
}

extraArgument 不用理會,這是新功能讓使用者客製化增加 thunk 的參數,action 會是我們傳入的 action creator,當 action creator 是一個 function,就執行 action creator function,如果不是就執行 next 帶入 action creator,正常的執行 dispatch。

redux applymiddleware

  • thunk source code
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) =>
    (next) =>
    (action) => {
      if (typeof action === "function") {
        return action(dispatch, getState, extraArgument);
      }

      return next(action);
    };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

redux thunk

  • 舊版 applyMiddleWare (github 只剩 typescript…)
// middlewares argument is pass thunk
export default function (...middlewares) {
  return (createStore) => (reducers, initialState, enhancer) => {
    const store = createStore(reducers, initialState, enhancer);
    const dispatch = store.dispatch;
    const chain = [];
    const middleWareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action),
    };

    chain = middlewares.map((middleware) => middleware(middlewareAPI));
    dispatch = compose(...chain)(store.dispatch); // store.dispatch or dispatch both work
    // compose will do following thing:
    /*
     * a, b, c ==> a(b(c())), indeed, it is just a reduce and store.dispatch will be an initial value
     */
    return {
      ...store,
      dispatch,
    };
  };
}

redux thunk code 很優美,完美的示範如何使用 redux 的 middleWare,邏輯清楚又不複雜。我一定不會說這篇文章是為了分享 redux thunk。

改天再來研究、分享更優美的 redux。

這兩個方法 batchredux thunk 都是目前專案都有用到的方法,至於其他就改天再另外介紹。 batch 因為與 react fiber 更新 component 機制有關,這部分較複雜,我對這塊沒有特別研究…,無法提供太多看法。

感謝閱讀,以上有錯誤再麻煩留言或私訊。