《三》redux-thunk 中间件

在之前的代码中,必须将网络请求的异步代码放到组件的生命周期中来完成。

// increase.js
import React, {PureComponent} from 'react'
import {connect} from 'react-redux'
import axios from 'axios'
import {increaseAction} from '../store/action'

class Increase extends PureComponent {
  handleIncrease = () => {
  	// 网络请求的异步代码
    axios.get('http://123.207.32.32:8000/home/multidata').then(res => {
      const count = res.data.data.banner.list.length
      this.props.handleCountIncrease(count)
    })
  }

  render() {
    return (
      <div>
        <button onClick={this.handleIncrease}>增加</button>
      </div>
    )
  }
}

const mapDispatchToProps = dispatch => ({
  handleCountIncrease: count => {
    dispatch(increaseAction(count))
  }
})
export default connect(null, mapDispatchToProps)(Increase)

但实际上,网络请求到的数据也属于状态管理的一部分,更好的做法是将它们也交给 Redux 来管理。

由于 Action 是一个对象,所以无法在 Action 中进行网络请求; Reducer 是一个纯函数,不能有副作用,所以也不能在 Reducer 中进行网络请求。因此只能尝试对 dispatch() 进行处理。
请添加图片描述

Redux 中间件:

Redux 引入了中间件 Middleware 的概念。

Redux 中间件的核心是在 dispatch 之后,到达 Reducer 之前进行一些扩展。

实现原理是在 dispatch 派发 action 的时候对其进行拦截,通过 Monkey Patching 的方式对原本的 dispatch 进行修改,让其指向一个新函数,在新函数中执行需要的逻辑后再使用原本的 dispatch 真正地派发 action。其实就是对 Redux 的 dispatch 进行了一层封装,增强了 dispatch 的能力。

Monkey Patching 猴补丁:通过篡改现有的代码,对程序逻辑进行修改。

可以利用 Redux 中间件来进行日志记录(redux-logger)、执行异步操作(redux-thunk)等。

没有中间件:store.dispatch() 就是 Redux 自己的 dispatch 方法,用来发起状态更新。dispatch() => reducer。
使用中间件:store.dispatch() 就是中间件封装后的 dispatch,但是最终还是一定会调用 Redux 自己的 dispatch 方法发起状态更新。dispatch() => 执行中间件代码 => reducer。

在 Redux 中注册中间件。

// 以 redux-thunk 为例
// 1. 从 redux 中引入 applyMiddleware 方法,以逗号分割可传入多个中间件
import {createStore, applyMiddleware} from 'redux'
// 2. 从 react-thunk 中引入中间件 thunk
import thunk from 'redux-thunk'
import reducer from './reducer'

// 3. createStore() 可传入第二个参数来注册中间件,对 dispatch 进行增强
export default createStore(reducer, applyMiddleware(thunk))

手动实现中间件:

实现一个日志打印的中间件:在派发 action 之前打印 action,在派发 action 之后打印 state。

// store/index.js
import {createStore} from 'redux'
import reducer from './features/count'

const store = createStore(reducer)

function log(store) {
  // 1. 保存真正的 dispatch
  const next = store.dispatch

  function logAndDispatch(action) {
    console.log('当前派发的 action', action)

    // 3. 使用真正的 dispatch 派发 action
    next(action)

    console.log('派发之后的结果', store.getState())
  }

  // 2. 修改 dispatch 的指向。之后通过 dispatch 派发 action 的时候,执行的将会是 logAndDispatch
  store.dispatch = logAndDispatch
}
log(store)

export default store

实现一个异步操作的中间件。主要就是可以让 dispatch 派发一个函数,就可以在这个函数内部做任何事情了

// store/index.js
import {createStore} from 'redux'
import reducer from './features/count'

const store = createStore(reducer)

function thunk(store) {
  // 1. 保存真正的 dispatch
  const next = store.dispatch

  function dispatchThunk(action) {
    // 如果判断到 action 是一个函数,则执行这个函数;否则使用真正的 dispatch 派发 action
    if (typeof action === 'function') {
      action(next, store.getState)
    } else {
      next(action)
    }
  }

  // 2. 修改 dispatch 的指向。之后通过 dispatch 派发 action 的时候,执行的将会是 dispatchThunk
  store.dispatch = dispatchThunk
}
thunk(store)

export default store

redux-thunk 中间件:

redux-thunk 的主要功能就是可以让 dispatch 派发一个函数,那么,就可以在这个函数内部做任何事情了(例如:进行网络请求等)。因此,通常使用 redux-thunk 中间件来处理异步操作。

Redux 中的 dispatch 正常情况下只能派发一个对象。

redux-thunk 的核心代码其实就是判断每个经过它的 action:如果是 function 类型,就调用这个 function,而不是任由让它到达 reducer。因为 reducer 是个纯函数,Redux 规定到达 reducer 的 action 必须是一个 plain object 类型。
请添加图片描述

安装:

npm install redux-thunk

使用:

  1. 注册 redux-thunk 中间件来对 dispatch 进行增强。
    // store/index.js
    // 从 redux 中引入 applyMiddleware 方法,以逗号分割可传入多个中间件
    import {createStore, applyMiddleware} from 'redux'
    // 从 react-thunk 中引入中间件 thunk
    import thunk from 'redux-thunk'
    import reducer from './reducer'
    
    // createStore() 可传入第二个参数来注册中间件,对 dispatch 进行增强
    export default createStore(reducer, applyMiddleware(thunk))
    
  2. 在组件中,通过 store.dispatch() 派发的时候派发一个函数,该函数会被自动执行,并传入 dispatch 和 getState 两个方法作为其参数,在函数内部执行完异步操作之后,再通过 dispatch 参数派发一个 Action 对象。

    也就是说,开始派发的函数的作用只是可以在其内部进行异步操作,最终派发出去的仍然是一个 Action 对象,Reducer 会在接收到该 Action 后返回最新的 State。

    // increase.js
    import React, {PureComponent} from 'react'
    import {connect} from 'react-redux'
    import {increaseAction} from '../store/action'
    
    class Increase extends PureComponent {
      handleIncrease = () => {
        this.props.handleCountDecrease()
      }
    
      render() {
        return (
          <div>
            <button onClick={this.handleIncrease}>增加</button>
          </div>
        )
      }
    }
    
    const mapDispatchToProps = dispatch => ({
      handleCountDecrease: () => {
        // store.dispatch() 派发一个函数,派发的函数会被自动执行
        dispatch(increaseAction())
      }
    })
    export default connect(null, mapDispatchToProps)(Increase)
    
    // store/action.js
    import axios from 'axios'
    
    // 创建 Action 的 Action Creator
    export const increaseAction = () => {
      // 派发的函数会接收 Store 中的 dispatch 和 getState 两个方法作为参数
      return (dispatch, getState) => {
        axios.get('http://123.207.32.32:8000/home/multidata').then(res => {
          const count = res.data.data.banner.list.length
          // 在派发的函数内部执行完异步操作之后,再通过 dispatch 派发一个 Action 对象
          dispatch({
            type: 'increase',
            count,
          })
        })
      }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值