关于 redux-thunk 的作用,认识,理解

关于 redux-thunk 的作用,认识,理解

看这篇文章之前,如果你已经看到一些 redux-thunk 的教程,是不是觉得一头雾水,redux-thunk 到底有什么作用,用在哪里,代码不仅没有简化,反而还增加?基于我初学的一些疑惑和后来疯狂的百度,总结了一下

首先来一段代码示例

如果我们有一个异步请求,获取数据展示在页面上。假设 redux 都是已经写好了。我们只模拟请求阶段

// App.js
import React, { Component } from 'react'
import store from './store/index'
import axios from 'axios'

class App extends Component {
  constructor(props) {
    super(props)
    this.state = store.getState()
    // store 监听更新,并且自动赋值到页面上
    store.subscribe(() => this.setState(store.getState()))
  }

  // 在页面组件挂载后,请求一个模拟的接口,获取一个todoList列表
  componentDidMount() {
    axios
      .get('http://rap2.taobao.org:38080/app/mock/246209/todoList')
      .then(res => {
        store.dispatch({ type: 'GET_LIST', value: res.data.data })
      })
      .catch(res => {})
  }

  render() {
    return (
      <ul>
        {this.list.map((item, index) => {
          return <li key={index}>{item}</li>
        })}
      </ul>
    )
  }
}

export default App

先来看下这段代码有什么问题:

  1. 在生命周期函数中请求了一个接口,那如果这个页面渲染需要多个接口呢,那生命周期代码量就会非常的大(可以把这些请求抽成方法啊,然后生命周期中只调用方法就简洁了)。没错,写成方法真是我们要做的

  2. 不利于测试,在我们没写成方法之前,如果我们想单元测试下这个接口,模拟一些数据,我们很难在生命周期中模拟


使用 redux-thunk 来优化代码

新建一个 js 文件,来统一放我们请求/操作的代码

  • 我们定义一个 getTodoList 方法
// src/store/actionCreators.js

// 这个方法看上去像一个闭包。因为redux-thunk是可以接收一个函数的,所以我们来返回一个函数
export const getTodoList = () => {
  return dispatch => {
    axios
      .get('http://rap2.taobao.org:38080/app/mock/246209/todoList')
      .then(res => {
        console.log(res.data.data)
        dispatch({ type: GET_LIST, value: res.data.data })
      })
      .catch(res => {})
  }
}
  • 在 App.js 页面上使用
// App.js
import React, { Component } from 'react'
import store from './store/index'
// ! 异同 ! 这里我们不在需要引入axios。而是引入我们的方法
import { getTodoList } from './store/actionCreators'

class App extends Component {
  constructor(props) {
    super(props)
    this.state = store.getState()
    // store 监听更新,并且自动赋值到页面上
    store.subscribe(() => this.setState(store.getState()))
  }

  componentDidMount() {
    // ! 异同 ! 这里还是在生命周期获取数据。
    // 不过这里我们执行 getTodoList() 返回的是一个函数
    store.dispatch(getTodoList())
  }

  render() {
    return (
      <ul>
        {this.list.map((item, index) => {
          return <li key={index}>{item}</li>
        })}
      </ul>
    )
  }
}
export default App

对比着看,2 段代码没有什么不同,反而好像了些代码,那下面我们就来细细分析


redux-thunk 作用是什么

redux-thunk 可以让 store.dispatch 变成可以接收一个函数/一个对象的中间件

  • redux-thunk 源码
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument)
    }

    return next(action)
  }
}

const thunk = createThunkMiddleware()
thunk.withExtraArgument = createThunkMiddleware

export default thunk

让原本只能接受对象的 store.dispatch 变成可以接收对象/方法,并且如果接收了一个方法后自动执行该方法,而不触发 redux 的 store 更新。

这有点拗口,来一个张图:
关于 redux-thunk 的作用,认识,理解_第1张图片

而且 redux-thunk 在执行我们的函数后,可以给我们返回 dispatch.在 redux-thunk 源码的第四行。那么我们可以在异步回调后直接拿到 dispatch 来继续派发我们的 redux 的事件,并且把异步函数抽象成了一个方法,使用 store.dispatch 来触发该方法。

譬如我们有一个加入购物车功能的接口,在商品详情可以加入购物车,在购物车可以添加商品的数量,那这个接口是可以复用的,抽离了之后,就可以在不同界面一起调用这个接口。从而实现代码复用

如果说 redux-thunk 是为了异步代码复用,为什么不定义一个方法调用,一定要用 redux-thunk 呢?

难道我们写成一个公共函数,然后在函数中引入 sotre 他不香吗?这样全部方法都可以获得 store 对象,也能调用 store.dispatch 方法来派发事件啊

这个事情要从 redux 设计说起:

  1. 它强制了 store 必须是一个单例:这对服务端渲染很不友好,因为对于不同的用户或者说请求,它都应该有个独立的 store

  2. 不易于测试:因为使用了外部引用的 store,你没办法方便地 mock 一个 store 用来测试,也不能控制 store 的状态

ps: 以上 2 短话摘录自:为什么要使用 redux-thunk。包括上面的图也是盗用这位大佬的。


总结

redux-thunk 的功能介绍就说道这里了。在刚开始学的时候,的确很难理解,明明代码没简化,还多引了一个插件,这到底图什么?

一切为了代码复用,可能代码量还少,看不出来优势,等到多个地方用到同一段代码,就知道代码复用是多爽的一件事,其次就是 redux-thunk 强化了 store.dispatch 方法。而且遵循了 redux强制store必须是一个单例的规则。也方便做局部测试

你可能感兴趣的:(react)