[Redux] Redux Thunk 小筆記
Intro
之前筆記有記錄過,Redux 其中一個很重要的概念,就是要保持 reducers
是完全的 pure 的,那所以進行 AJAX 這種充滿副作用的行為時,就需要在 actions
解決。
所以一個可能的場景就是想要 fetch
資料時,先發一個 action
。在這個 action
內先做 fetch
,等拿到資料後,再 dispatch
結果給 reducers
來完成,如此就可以將不確定性(例如連線失敗沒拿到資料)留在 actions
保持 reducers
的 pure 特性。
但正常 Redux 的 actionCreator
就是直接 dispatch
了,像這樣:
export const deleteTodo = todo => ({ type: 'deleteTodo', todo });
所以我們可以透過 redux-thunk
幫忙在 actionCreator
根據狀況 dispatch
不同的事件和內容。
Redux-Thunk
先讀一下 redux-thunk
官方介紹:
Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods
dispatch
andgetState
as parameters.
再來讀一下 redux-thunk
的原始碼:
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
這個4千多個星星的源始碼就只有短短14行。
可以看得出來,它主要只是一個 mddileware
。當發現 action
不是正常的 Object
而是 function
時,就會將 dispatch
, getState
等餵進執行,回傳得到正常的 Object
再交給 reducers
。
一個完整的例子:
const addTodoRequest = () => (
{ type: 'ADD_TODO_REQUEST' }
);
const addTodoSuccess = (todo) => (
{
type: 'ADD_TODO_SUCCESS',
todo,
};
);
const addTodoFailure = (err) => (
{
type: 'ADD_TODO_FAILURE',
err,
};
);
const addTodo = (todo) => (dispatch) => {
dispatch(addTaskRequest());
return fetch('http://www.example.com/api', {
method: 'POST',
body: JSON.stringify({
todo
})
})
.then(res => {
dispatch(addTodoSuccess(todo));
})
.catch(err => dispatch(addTodoFailure(err)));
};
所以當 addTodo
被執行時,到 redux-thunk
這個 middleware
時,會先被擋下來。
餵入 dispatch
後執行,這時會先 dispatch(addTaskRequest());
給 reducers
, 然後根據成功與否,接下來執行 dispatch(addTodoSuccess(todo));
或 dispatch(addTodoFailure(err))
站在 reducers
的角度,就是當收到 addTaskRequest()
時,就可以改變 state
讓頁面顯示”載入中”之類的符號,直到得到 addTodoSuccess(todo)
或 addTodoFailure(err)
時,才再改變 state
讓畫面顯示”新增成功”或”新增失敗”等訊息。
所以結論就是 redux-thunk
透過增加一個 middleware
,可以豐富本來 actions
能做的事。