纵横研究院React技术专题社区

【学习笔记 】React ⑦ 使用Redux中间件处理异步流

2019-12-16  本文已影响0人  Moombahton

    在最开始编写项目代码的时候,ajax请求放在生命周期函数componentDidMount()中,但是随着代码量增加,componentDidMount()中有越来越多的逻辑,因此引入中间件middleware,将ajax请求做统一管理,复杂的逻辑放在action处理对之后维护以后以自动化测试都提供了很大的帮助。

何为中间件?

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中间件在派发action以及它到达reducer之间提供了第三方扩展。使用Redux中间件进行日志记录、崩溃报告、与异步API交谈、路由等等。

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

    简单来说middleware指的是actionstore之间,对dispatch的封装和升级,使用middleware之后,action既可以是一个对象,也可以是一个函数

增加中间件后的数据流

Redux标准流程
1.页面派发一个action
2.通过dispatch方法派发给store(action是一个对象)
3.store接收到action,连同之前的state传给reducer
4.reducer返回一个新的数据给store
5.store去改变自己的state

增加middleware之后,Data Flow是下图这样的

Redux Data Flow

    使用Redux中间件后流程,调用dispatch()方法,根据参数的不同,执行不同的流程。如果参数是对象就把这个对象直接传递给store,如果参数是函数,就先执行这个函数,执行之后如果需要调用store,那这个函数再去调用store

Redux处理异步流

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可以返回一个函数啦🤣)

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中的数据

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获取数据

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

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

适用于非常大型复杂的项目
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.创建sagas.js文件

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

4.修改Todolist.js中获取数据的方法

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

5.补充逻辑
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('网络请求失败')
    }
}

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

export default mySaga;

(完)

上一篇下一篇

猜你喜欢

热点阅读