回顧
在使用 Reudx 時如果只是基本的需求改變狀態,只要發起(dispatch)一個 action 就可以更改 store 中的狀態
// store
store.dispatch({
type: 'CHANGE_USER_FIELD',
payload: value
})
不過通常最難處理的事情就是 side effect(副作用),這樣聽起來也許太抽象,其實就是我們去做一些不是直接在 JavaScript 立即完成或能執行結果的事情,可能必須要花一點時間執行並等待結果,因為 JavaScript 的 single thread 機制,會讓這些事情擺在旁邊做,然後繼續執行接下來的動作,因此如果遇到以下狀況,例如需要等待資料庫回傳一筆資料像是 API
// store
const echoPayload = payload => console.log(payload);
const fetchUsers = () => {
setTimeout(() => ({ name: 'Whien', age: 18 }), 2000);
};
const users = fetchUsers();
echoPayload(users);
無論怎麼跑,users 一直都會得到 undefined,因為 setTimeout 並不會被 lock 住,而是丟到另一個 stack(web api) 等待時間,並且繼續往下進行,因此這時 echo 出來的 payload 就會得到 undefined,所以通常我們會這麼解決
// store
const echoPayload = payload => console.log(payload);
const fetchUsers = callback => {
setTimeout(() => {
let users = { name: 'Whien', age: 18 };
callback(users);
}, 2000);
};
fetchUsers(echoPayload);
利用 callback 的方式,等到確定資料回來後,我們在執行 echo,這麼一來就可以順利的將我們結果呈現 { name: ‘Whien’, age: 18 },但通常現實世界沒有這麼容易(人生好難),簡單介紹一下,直接進入 Redux 吧!
建立 Redux Store 環境
配置好所有的 Redux 環境
yarn add redux react-redux
建立好 store

直接 dispatch 一個 action 來抓取 users 資料


不過這是沒有任何 side effect 的狀態下,也就是原本就已經擁有 users 的資料了,但如果在沒有任何 users 的資料,而需要跟外部資料庫拿取時,該怎麼辦呢?我們可能會這樣做
首先將發起 action 改為 function 等待 users 資料進來,然後 return 一個一樣的 reducer 表達式物件

等待 side effect (setTimeout) 完成後,再呼叫 dispatch

這麼一來也會得到相同的結果

但這麼做太麻煩了,我們必須要在任何可能的地方加入這樣的一個模式,這麼一來就會變得非常雜亂,於是出現了 redux middleware 來幫助我們完成這件事情,middleware 講簡單點就是當資料進入後,將資料拉到另一個空間,進行另一種的變更改造,並且可以一次流經非常多的 middleware,只要最後再以一樣的方式流回最後處理結果,當然這個空間我們可以額外丟許多參數進去,接下來要進入 redux-thunk 這個 middleware。
安裝 redux-thunk
yarn add redux-thunk
改動一下原本的程式碼,讓 redux 允許使用 middleware 並且加入 redux-thunk


redux-thunk 是一個閉包(closure),會回傳一個帶有 (dispatch) 的方法,這麼一來就可以在 action 中呼叫 dispatch,而不用再奇怪的地方呼叫了,大概會長這樣子


通常用到這裡時,redux-thunk 已經足夠應付大部分 side effect 的使用情況,但當邏輯一多,每次的 dispatch 不再是這麼單純,甚至要加上許多「高級」的用法,cancel、race … 等等的時候怎麼辦呢?這時候就要靠更高級的 middleware 來控制流程,像是 redux-sage,接下會記錄關於 redux-saga 的用法。