Redux store 僅支持同步數(shù)據(jù)流。
使用 redux-thunk、redux-saga、redux-promise 等中間件可以幫助在 Redux 應(yīng)用中實(shí)現(xiàn)異步性。
1、redux-thunk是作為redux的 middleware 存在的,用法和普通 middleware 的用法是一樣的,注冊(cè) middleware 的代碼如下:
import thunkMiddleware from 'redux-thunk'
const store = createStore(reducer, applyMiddleware(thunkMiddleware))
redux-thunk主要的功能就是可以讓我們dispatch一個(gè)函數(shù),而不只是普通的 Object
原理:核心代碼其實(shí)只有兩行,就是判斷每個(gè)經(jīng)過它的action:如果是function類型,就調(diào)用這個(gè)function(并傳入 dispatch 和 getState 及 extraArgument 為參數(shù)),而不是任由讓它到達(dá) reducer,因?yàn)?reducer 是個(gè)純函數(shù),Redux 規(guī)定到達(dá) reducer 的 action 必須是一個(gè) plain object 類型。
使用場(chǎng)景:
// 用于發(fā)起登錄請(qǐng)求,并處理請(qǐng)求結(jié)果
// 接受參數(shù)用戶名,并返回一個(gè)函數(shù)(參數(shù)為dispatch)
const login = (userName) => (dispatch) => {
dispatch({ type: 'loginStart' })
request.post('/api/login', { data: userName }, () => {
dispatch({ type: 'loginSuccess', payload: userName })
})
}
store.dispatch(login('Lucy'))
示例代碼中,我們定義了 login 函數(shù)做 API 請(qǐng)求,在請(qǐng)求發(fā)出前我們可能需要展示一個(gè)全局的 loading bar,在請(qǐng)求結(jié)束后我們又需要將請(qǐng)求結(jié)果存儲(chǔ)到 redux store 中。這都需要用到 redux 的 dispatch。
2、redux-saga
基于 es6 Generator語法,將異步操作邏輯存放在一個(gè)地方進(jìn)行集中處理,通過 yield 關(guān)鍵字,可以讓函數(shù)的執(zhí)行流掛起。
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware];
const store = createStore(appReducer, applyMiddleware(...middlewares));
sagaMiddleware.run(rootSaga);
監(jiān)聽被dispatch的actions,當(dāng)接收到action或者知道其被觸發(fā)時(shí),調(diào)用worker saga執(zhí)行任務(wù)
原理:redux-saga相當(dāng)于在Redux原有數(shù)據(jù)流中多了一層,通過對(duì)Action進(jìn)行監(jiān)聽,從而捕獲到監(jiān)聽的Action,然后可以派生一個(gè)新的任務(wù)對(duì)state進(jìn)行維護(hù)(這個(gè)看項(xiàng)目本身的需求),通過更改的state驅(qū)動(dòng)View的變更
import { fork, all, call, put, takeEvery, takeLatest } from 'redux-saga/effects'
fork 創(chuàng)建一個(gè)新的進(jìn)程或者線程,并發(fā)發(fā)送請(qǐng)求
call: 發(fā)送 api 請(qǐng)求 異步執(zhí)行
all:all 跟 fork 一樣,同時(shí)并發(fā)多個(gè) action,沒有順序
put: put 發(fā)送對(duì)應(yīng)的 dispatch,觸發(fā)對(duì)應(yīng)的 action
take: 是用來監(jiān)聽action,返回的是監(jiān)聽到的action對(duì)象 暫停Generator
匹配的action被發(fā)起時(shí),恢復(fù)執(zhí)行。take結(jié)合fork,可以實(shí)現(xiàn)takeEvery和takeLatest的效果
takeEvery: 監(jiān)聽對(duì)應(yīng)的 action 每一次 dispatch 都會(huì)觸發(fā)
takeLatest: 監(jiān)聽對(duì)應(yīng)的 action 只會(huì)觸發(fā)最后一次 dispatch, 例如:點(diǎn)擊一個(gè)新增的按鈕,2s 后觸發(fā)新增動(dòng)作,在2s內(nèi)不斷點(diǎn)擊按鈕,這時(shí)候,只有最后一次點(diǎn)擊是有效的
cancel: 指示 middleware 取消之前的 fork 任務(wù),cancel 是一個(gè)無阻塞 Effect。race 競(jìng)速執(zhí)行多個(gè)任務(wù)
3.redux-promise
使用redux-promise中間件,允許action是一個(gè)promise
原理:如果action是一個(gè)promise,則會(huì)等待promise完成,將完成的結(jié)果作為action觸發(fā),如果action不是一個(gè)promise,則判斷其payload是否是一個(gè)promise,如果是,等待promise完成,然后將得到的結(jié)果作為payload的值觸發(fā)。