redux-thunk、redux-saga、react-redux中间件的使用

1,516 阅读2分钟

demo源码: https://github.com/recall-lidemin/todolist-demo.git

什么是Redux中间件?

  • redux中间件的中间指的是action和store中间
  • redux中间件实际是对dispatch方法的封装或升级,升级之后,dispatch就既能接收对象,也能接收函数
  • 补充:中间件指的是redux的中间件,不是react的。

1.redux-thunk

  • 安装redux-thunk yarn add redux-thunk
  • 注册中间件,使用applyMiddleware
import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import reducer from './reducer'

// 为了thunk与devtools一起使用
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
 ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
 : compose
const enhancer = composeEnhancers(applyMiddleware(thunk))
const store = createStore(reducer, enhancer)

export default store
  • 在action中使用,使用了redux-thunk中间件之后,action返回就可以是一个函数,不再必须是对象,在这个函数中,我们可以发起异步请求来获取数据,而且返回的函数会被注入dispatch这个参数,我们不再需要引入store
store/actionCreators.js

export const getTodoList = () => {
  return async (dispatch) => {
    const res = await axios.get('http://localhost:3000/list')
    const action = initListAction(res.data)
    dispatch(action)
  }
}
  • 在页面组件中
import {getTodoList} from './store/actionCreators'
const TodoList = () => {
  // 发送请求获取数据
  const getList = async () => {
    const action = getTodoList()
    store.dispatch(action) // 注入dispatch
  }
}

2.redux-saga

  • 安装redux-saga yarn add redux-saga
  • 注册redux-saga
import { createStore, applyMiddleware, compose } from 'redux'
import createSagaMiddleware from 'redux-saga'
import reducer from './reducer'
import mySaga from './sagas'

// 创建saga中间件
const sagaMiddleware = createSagaMiddleware()
// 开启devtools
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
  ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
  : compose
// 注册saga
const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware))
const store = createStore(reducer, enhancer)
// 运行saga文件
sagaMiddleware.run(mySaga)

export default store
  • 在saga.js中使用
import { call, put, takeEvery, takeLatest } from 'redux-saga/effects'
import { GET_INIT_LIST } from './actionTypes'
import { initListAction } from './actionCreators'
import axios from 'axios'

// 处理函数,可以在此进行异步请求,这里使用的es6的Genegetor函数
function* fetchList() {
  try {
    const res = yield axios.get('http://localhost:3000/list')
    const action = initListAction(res.data)
    yield put(action)
  } catch (error) {
    // do null
  }
}
// 监听页面action的派发,执行对应的函数
function* mySaga() {
  yield takeEvery(GET_INIT_LIST, fetchList)
}

export default mySaga
  • 在页面组件中分发,触发saga监听
  // 使用redux-saga
  const getList = async () => {
    const action = getTodoList()
    store.dispatch(action)
  }

3.react-redux

  • 安装react-redux yarn add react-redux
  • 创建store
import { createStore } from 'redux'
import reducer from './reducers'

const store = createStore(reducer)

export default store
  • 连接react-redux,使用Provider,注册到上下文
import React from 'react'
import ReactDOM from 'react-dom'
import 'antd/dist/antd.css'
import TodoList from './todolist'
import { Provider } from 'react-redux'
import store from './react-redux'

// react-redux连接store
ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <TodoList />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
  • 在组件中通过connect使用
import React from 'react'
import { Button, Input, List } from 'antd'
import { connect } from 'react-redux'

const TodoList = (props) => {
  const { inputValue, list, handleChange, handleAdd, handleDel } = props

  return (
    <>
      <div style={{ display: 'flex' }}>
        <Input
          style={{ width: 200 }}
          value={inputValue}
          onChange={handleChange}
        />
        <Button type="primary" onClick={handleAdd}>
          提交
        </Button>
      </div>
      <List
        size="large"
        bordered
        dataSource={list}
        renderItem={(item, index) => (
          <List.Item key={item} onClick={() => handleDel(index)}>
            {item}
          </List.Item>
        )}
      />
    </>
  )
}

// 将state映射到props中
const mapStateToProps = (state) => {
  return {
    inputValue: state.inputValue,
    list: state.list,
  }
}
// 将dispatch映射到props中,可以在此处写处理函数,也可以将dispatch从组件props中解构出来,直接在组件中进行dispatch分发,此处就可以不必写,只传一个mapStateToProps参数即可
const mapDispatchToProps = (dispatch) => {
  return {
    handleChange(e) {
      dispatch({
        type: 'change_input_value',
        value: e.target.value,
      })
    },
    handleAdd() {
      dispatch({
        type: 'add_list',
      })
    },
    handleDel(index) {
      dispatch({
        type: 'del_list',
        value: index,
      })
    },
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(TodoList)

  • 数据处理逻辑同样在reducer中