Skip to main content

[Redux] Redux Thunk

TL;DR

  • 從原始碼中可以知道,redux-thunk 真的只是用來讓開發者能夠在 redux 中呼叫非同步請求,但它沒有除了其他 API 請求時需要處理的問題(例如,dedupe、race condition、發出請求和得到結果的順序)
  • thunk 是一個 function 讓我們能夠處理 async 的操作,thunk function 是能接受 dispatch 和 getState 作為參數的函式,用來產生 think function 的函式則稱作 thunk creator
// const thunkCreator = () => (dispatch, getState) => {...}
// const thunkFunction = (dispatch, getState) => {...}

// incrementAsync 是 thunkCreate,執行後會回傳 thunk function
export const incrementAsync =
(amount: number): AppThunk =>
(dispatch, getState) => {
setTimeout(() => {
dispatch(incrementByAmount(amount));
}, 1000);
};

// 使用 thunk function
store.dispatch(incrementAsync(5));
note

從原本的英文來說,thunk 單純是指一個函式回傳了另一個函式時,那個「被回傳出來的函式」(What the heck is a 'thunk'?)。


Redux Thunk middleware 讓你可以撰寫一個回傳 function 而非 action 的 action creators,透過 thunk 可以讓你控制發送(dispatch)一個 action 的時間點,因此適合用來處理非同步取得的資料狀態,或者是在特定條件符合的情況下才發送。

使用

使用 redux-thunk 時,action creators 會回傳的不是物件,而是一個帶有 dispatch, getState, extraArgument 參數的 async function,並在這個 async function 會再去執行 dispatch 方法,來通知到 reducer:

export const FETCH_USERS = 'fetch_users';
export const fetchUsers = () => async (dispatch, getState, axiosInstance) => {
const res = await axiosInstance.get('/users');

dispatch({
type: FETCH_USERS,
payload: res,
});
};

async function 執行後本身也是一個 Promise,可以透過 .then() 繼續串接。

Source Code

function createThunkMiddleware(extraArgument) {
// 這是 middleware 基本的寫法
return ({ dispatch, getState }) =>
(next) =>
(action) => {
// action 就是透過 action creators 傳進來的東西,
// 在 redux-thunk 中會是 async function
if (typeof action === 'function') {
// 在這裡回傳「執行後的 async function」
return action(dispatch, getState, extraArgument);
}

// 如果傳進來的 action 不是 function,則當成一般的 action 處理
return next(action);
};
}

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

export default thunk;