第 29 天 !
剩~兩~天~!
昨天已經把整個 redux 的流程給接起來了,
從 store 讀取資料還有用 action 去改變 store , 這些我們大概都展示一次 ,
但是很多操作其實並不侷限在本地端,
比較正確來說,
現在所做的一系列這樣一步接一步的動作,我們稱它為 sync(同步) ,
但總有一些操作是我們不會去等,直接前往下一步動作,但會先設定好操作結束後的相關動作,等它去觸發,我們稱它為 async(非同步) ,
在 redux 要處理 async , action 跟 reducer 都不能做這部份處理,
我們必須加入 middleware ,
redux 允許我們在這裡處理 async 的相關操作,
那... middleware 會在什麼事後觸發呢?
老樣子, 這是官方提供的流程圖

可以看到當我們的 action 去觸發 dispatch 時候,在之前並不會直接進入 reducer , 而是會先進入 middleware 去跑一遍之後,再進去 reducer,
加入 middleware 後的流程應該是:
那如何加入 middleware ?
第一先選擇我們要使用的 middleware,
就是我們今天要介紹的 redux-thunk,
先來安裝:
yarn add redux-thunk
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;
....嗯,這就是全部了,
有興趣可以去 thunk 的 github 上看看,
它其實很簡單的去建立了,在 middleware 的 async 操作環境,
看程式碼其實可以知道的是,middleware 提供了幾個參數,
蠻直白的,
getState ,取得 store 的資料,
next ,代表是的這 action 直接往下一個 middleware 走,假如沒有就進去 reducer ,
action , 當前發送的 action,
extraArgument 這個是 thunk 2.0 才有的參數,主要一開始設定的時候可以帶入額外的參數給 middleware
再來就是 thunk 只是很簡單的去判斷 action 送進來的是不是 function ,
是的話把 dispatch & getState & extraArgument 帶入到這個 function
也就是說要做 sync 就照原樣送 action ,
想要做 async 就把 action 用成 function,
再來就是把 thunk 塞入 redux 裡,
使用 redux 提供的 applyMiddleware 來把 thunk 塞入 redux ,
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducer';
export default function configureStore() {
return createStore(rootReducer, applyMiddleware(thunk));
}
假如有需要額外塞資訊進去,
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducer';
export default function configureStore(api) {
return createStore(
rootReducer,
applyMiddleware(thunk).withExtraArgument({ api })
);
}
這樣 thunk 就進入到 redux 流程裡了,
我們試著把 TodoList 的 新增用 thunk 實作
const fakeAsync = payload => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(payload);
}, 3000);
});
};
export const insertToDoThunk = payload => {
return async dispatch => {
const item = await fakeAsync(payload);
dispatch(insertToDoAction(item));
};
};
因為我們沒有 api 所以設定一個 fakeAsync 來模擬 async,
那流程是 呼叫 insertToDoThunk 會延遲 3 秒,
之後讓 dispatch 執行 insertToDoAction
在 Header component 把 insertToDoAction 換成 insertToDoThunk
結果是:
