深入浅出之redux-thunk

有没有人跟我一样居家待业的,面试现在都要求附上自己的博客或者项目地址了(lipu)。

今天花时间深入学习一下 redux-thunk 的源码。

thunkreact 中作为 redux 的中间件,方便我们将业务逻辑抽离 出来,主要是副作用逻辑

用法

主要是通过参数 的形式传入到 applyMiddleware 方法中

ts 复制代码
import {createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
const store = createStore(
    reducer,
    applyMiddleware(thunk)
)

深入

先看thunk源码:

ts 复制代码
function createThunkMiddleware<
  State = any,
  BasicAction extends Action = AnyAction,
  ExtraThunkArg = undefined
>(extraArgument?: ExtraThunkArg) {
  const middleware: ThunkMiddleware<State, BasicAction, ExtraThunkArg> =
    ({ dispatch, getState }) =>
    next =>
    action => {
      if (typeof action === 'function') {
        return action(dispatch, getState, extraArgument)
      }

      return next(action)
    }
  return middleware
}

export const thunk = createThunkMiddleware()

可以看到thunk通过createThunkMiddleware的执行返回了一个函数,同时附带一个参数对象,包含 dispatchgetState那么这个参数是怎么来的?

在用法中可以看出thunk作为了applyMiddleware的参数,那继续看applyMiddleware的源码:

ts 复制代码
export default function applyMiddleware(
  ...middlewares: Middleware[]
): StoreEnhancer<any> {
  return createStore => (reducer, preloadedState) => {
    const store = createStore(reducer, preloadedState)
    let dispatch: Dispatch = () => {
      throw new Error(
        'Dispatching while constructing your middleware is not allowed. ' +
          'Other middleware would not be applied to this dispatch.'
      )
    }

    const middlewareAPI: MiddlewareAPI = {
      getState: store.getState,
      dispatch: (action, ...args) => dispatch(action, ...args)
    }
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose<typeof dispatch>(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

applyMiddleware这个函数执行后返回两层函数

箭头函数在不写大括号的情况下会默认返回。

这个函数在用法中由createStore执行,并且是执行两层并传入相关参数:

ts 复制代码
return enhancer(createStore)(
  reducer,
  preloadedState as PreloadedState | undefined
)

applyMiddleware的第二层函数执行后创建了一个store const store = createStore(reducer, preloadedState) ,通过闭包拿到一开始的参数middlewares。

这里的middlewares为啥是一个函数类型的数组,传入的应该是一个函数,有没有同学解答一下,求教!

通过map将middlewareAPI对象传入middlewares.map(middleware => middleware(middlewareAPI))这也就是上面提到的,为什么createThunkMiddleware函数可以拿到dispatch和getState。

可以看到这个dispatch函数最后也是调用的dispatch,那么这个dispatch是怎么进行副作用处理呢?

ts 复制代码
dispatch = compose<typeof dispatch>(...chain)(store.dispatch)

dispatch是通过compose方法执行后进行赋值,那么继续看compose如何实现:

ts 复制代码
export default function compose(...funcs: Function[]) {
  if (funcs.length === 0) {
    return <T>(arg: T) => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args: any) => a(b(...args)))
}

可以看到compose通过数组长度判断,如果是一个中间件,直接返回,如果是多个,那么按顺序执行后返回,总之就是返回一个函数,然后又立即执行,并传入store的dispatch方法。所以thunk源码中的next其实就是store.dispatch方法。走到这里就会发现thunk最后就是输出了一个函数,用来判断action是否是一个函数

ts 复制代码
action => {
  if (typeof action === 'function') {
    return action(dispatch, getState, extraArgument)
  }

  return next(action)
}

当你dispatch中传入的action对象,就会走next,next就是applyMiddleware中compose函数执行后传入的dispatch,如果是一个function,就执行这个函数,这个函数理所当然的可以执行副作用,函数里的参数dispatch和getState是middlewares.map时传入的参数。

注意:两个dispatch方法其实是同一个引用

浅出

thunk在项目组件中使用就很简单了。

dispatch中的参数要么是一个偏平的action对象,要么就是一个函数,当然函数是不是副作用其实无所谓,不过一般不会有人脱裤子放屁,在函数中返回一个action对象吧。

相关推荐
Maimai1080836 分钟前
React Server Components 是什么?一文讲清 CSR、Server Components 与 Next.js 中的客户端/服务端组件
前端·javascript·css·react.js·前端框架·html·web3
前端进阶之旅17 小时前
React 18 并发特性实战指南:提升大型应用性能的关键技术
前端·react.js·前端框架
Maimai1080818 小时前
Next.js 16 缓存策略详解:从旧模型到 Cache Components
开发语言·前端·javascript·react.js·缓存·前端框架·reactjs
下北沢美食家18 小时前
React面试题
前端·javascript·react.js
有意义18 小时前
极简的React 实现一
前端·javascript·react.js
打小就很皮...18 小时前
实现可交互的泳道图组件(React)
前端·react.js·泳道图
大雷神19 小时前
HarmonyOS APP<玩转React>开源教程四:状态管理基础
react.js·开源·harmonyos
weixin_4462608521 小时前
提升开发效率的神器!快速选择编码上下文 — React Grab
前端·react.js·前端框架
Csvn21 小时前
使用 React Hooks 优化组件性能的 5 个技巧
前端·javascript·react.js
张一凡931 天前
告别 Redux 的繁琐,试试这个基于类模型的 React 状态管理库:easy-model
前端·react.js