目錄

透過 redux-thunk 處理非同步 action

首先必須知道幾個重點

  1. Redux 不會管你是否同步,想要更新 store ,就必須呼叫 dispatch()

  2. Redux 原始碼中,dispatch function 的實作是此 function 會回傳其第一個參數

1
2
// 也就是若執行以下這行,res 等於 action
const res = dispatch(action)
  1. 使用 redux-thunk 的話,若 action 為 function,thunk 會執行 action 並塞 dispatch 和 getState 作為參數: action(dispatch, getState)

知道以上幾點,就能完全透過原生的 Promise 來實作出有先後順序的action

範例一: 等待 API 結果的 action

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 這是一個 action creator,回傳一個 action
export const listData = (params) =>
  // 因為 action creator 製造出的 action 是 function
  // dispatch 這個 action 時,redux-thunk 就會注入兩個參數 dispatch 和 getState
  (dispatch, getState) => {
    // 發送一個物件 action ,改變 loading 狀態
    dispatch({ type: Actioin.LOADING });

    // 回傳一個 Promise
    return getDataApi(params)
      .then((res) => {
        // 當 promise resolved,表示資料載入完成,此時發送 action 改變 store
        dispatch({ type: Action.LOADED, payload: res })
      })
      .catch((e) => {
        dispatch({ type: Action.LOAD_FAIL})
      })
  }

當有了上面的 listData action creator

1
2
// 此時,data 等於 getDataApi(params) 這個 Promise
const data = await dispatch(listData(params));

範例二: 需先取得其他 API 的結果,再做其它事

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
export const waitListData = () =>
  (dispatch, getState) => {
    // 發送一個物件 action ,改變 loading 狀態
    dispatch({ type: Actioin.LOADING });

    // 回傳一個 Promise
    return dispatch(listData())
      .then(() => {
        // promise 有先後順序
        // 這個 block 一定是 listData.then() 執行完之後,再執行的
        // 故可以取得最新的 data
        const latestData = getState().data;

        // 接著就可以拿 latestData 做其他事了
        dispatch(closeLoadingMask());
      })
  }

此時,發送這個 action dispatch(waitListData())時會做的事有:

  1. dispatch(listData())
  2. 等 1. 的 promise resolved
  3. 進入 waitListData 的 then