【學(xué)習(xí)筆記 】React?⑦ 使用Redux中間件處理異步流

????在最開始編寫項(xiàng)目代碼的時(shí)候,ajax請求放在生命周期函數(shù)componentDidMount()中,但是隨著代碼量增加,componentDidMount()中有越來越多的邏輯,因此引入中間件middleware,將ajax請求做統(tǒng)一管理,復(fù)雜的邏輯放在action處理對之后維護(hù)以后以自動化測試都提供了很大的幫助。

何為中間件?

It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer. People use Redux middleware for logging, crash reporting, talking to an asynchronous API, routing, and more.
Redux中間件在派發(fā)action以及它到達(dá)reducer之間提供了第三方擴(kuò)展。使用Redux中間件進(jìn)行日志記錄、崩潰報(bào)告、與異步API交談、路由等等。

引自:https://redux.js.org/advanced/middleware

????簡單來說middleware指的是actionstore之間,對dispatch的封裝和升級,使用middleware之后,action既可以是一個(gè)對象,也可以是一個(gè)函數(shù)

增加中間件后的數(shù)據(jù)流

Redux標(biāo)準(zhǔn)流程
1.頁面派發(fā)一個(gè)action
2.通過dispatch方法派發(fā)給store(action是一個(gè)對象)
3.store接收到action,連同之前的state傳給reducer
4.reducer返回一個(gè)新的數(shù)據(jù)給store
5.store去改變自己的state

增加middleware之后,Data Flow是下圖這樣的

Redux Data Flow

????使用Redux中間件后流程,調(diào)用dispatch()方法,根據(jù)參數(shù)的不同,執(zhí)行不同的流程。如果參數(shù)是對象就把這個(gè)對象直接傳遞給store,如果參數(shù)是函數(shù),就先執(zhí)行這個(gè)函數(shù),執(zhí)行之后如果需要調(diào)用store,那這個(gè)函數(shù)再去調(diào)用store

Redux處理異步流

  • redux-thunk

github:https://github.com/reduxjs/redux-thunk

1.安裝redux-thunk

yarn add redux-thunk
  1. 修改store的配置
import { createStore, applyMiddleware, compose } from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk'

const composeEnhancers =
    typeof window === 'object' &&
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;

const enhancer = composeEnhancers(
    applyMiddleware(thunk),
    // other store enhancers if any
);
const store = createStore(reducer, enhancer);

export default store
// https://github.com/zalmoxisus/redux-devtools-extension

3.在action中編寫寫異步的代碼(action可以返回一個(gè)函數(shù)啦??)

export  const getTodoList = () => {
    return () => {
        axios.get('http://mock-api.com/Rz317OnM.mock/api/todolist')
            .then((res) => {
                console.log(res.data)
            })
            .catch( () => {alert('error')})
    }
}

4.通過reducer更新store中的數(shù)據(jù)

export  const getTodoList = () => {
    return (dispatch) => {
        axios.get('http://mock-api.com/Rz317OnM.mock/api/todolist')
            .then((res) => {
                console.log(res.data)
                const data = res.data
                const action = initListAction(data)
                dispatch(action)
            })
            .catch( () => {alert('error')})
    }
}

5.Todolist.js獲取數(shù)據(jù)

import { getInputChangeAction, getAddItemAction, getDeleteItemAction, getTodoList } from './store/actionCreators'

 componentDidMount () {
        const action = getTodoList()
        store.dispatch(action)
        console.log(action)
    }
  • redux-saga

適用于非常大型復(fù)雜的項(xiàng)目
github:https://github.com/redux-saga/redux-saga

1.安裝redux-saga

yarn add redux-saga

2.配置store/index.js

import { createStore, applyMiddleware, compose } from 'redux'
import createSagaMiddleware from 'redux-saga'
import reducer from './reducer'
import todoSagas from './sagas'

const sagaMiddleware = createSagaMiddleware()
const composeEnhancers =
   typeof window === 'object' &&
   window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware));
const store = createStore(reducer, enhancer);
sagaMiddleware.run(todoSagas)

export default store

3.創(chuàng)建sagas.js文件

//sagas文件一定要有 generator 函數(shù)
function* mySaga() {
}
export default mySaga;

4.修改Todolist.js中獲取數(shù)據(jù)的方法

  componentDidMount () {
        const action = getInitList()
        console.log(action)
        store.dispatch(action)
    }

5.補(bǔ)充邏輯
actionTypes.js

export const GET_INIT_LIST = 'get_init_list'

actionCreator.js

export const getInitList = () => ({
    type: GET_INIT_LIST
})

sagas.js

import { takeEvery, put } from 'redux-saga/effects'
import { GET_INIT_LIST } from './actionTypes'
import axios from 'axios'
import { initListAction } from './actionCreators'
function* getInitList() {
    try{
        const res = yield axios.get('http://mock-api.com/Rz317OnM.mock/api/todolist')
        const action = initListAction(res.data)
        yield put(action)
    } catch(e) {
        console.log('網(wǎng)絡(luò)請求失敗')
    }
}

// generator 函數(shù)
function* mySaga() {
    yield takeEvery(GET_INIT_LIST, getInitList);
}

export default mySaga;

(完)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容