什么是调度函数?

2025-06-08

什么是调度函数?

学习 Redux?或者useReducer?那么你很可能已经被这个dispatch函数的黑魔法搞得心烦意乱了🧙‍♂️!好吧,幸运的是你找到了这篇文章。我会帮你理解底层发生了什么,揭开背后的神秘面纱dispatch

https://images.unsplash.com/photo-1551269901-5c5e14c25df7?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb

是什么让调度如此困难?

学习 Redux 或 Reducer Hooks 可能会令人困惑,原因有几个。

首先,这两种流程都依赖于一种名为“函数式编程”的编程范式。以这种方式思考需要你转变对应用程序数据管理的思维模式。想要了解更多关于函数式编程的知识,请阅读本文的前半部分——JavaScript中的函数式编程:如何以及为什么。这里使这些模式变得困难的基本思想是,数据在函数之间流动,并且在状态更新和组件重新渲染之前,数据的形状通常会发生一些变化(甚至很大😬)。

其次 - 两种流程都将部分逻辑“抽象”成不同的函数。想想看。如果你使用 Redux,你调用一个 action 创建函数,然后……一个 reducer 被调用,并且state一个 和一个action object被传入。这是什么鬼?!😡 Reducer hook 流程少了一层抽象,但仍然有一些地方会让人感到困惑。

重建调度

我认为了解 dispatch 函数的构建方式确实有助于揭开 reducer 背后的神秘面纱。因此,让我们构建一个简单的 dispatch 实现,来了解一下从我们的视图中抽象出来的逻辑。我们从函数定义开始。



function dispatch() {

}


Enter fullscreen mode Exit fullscreen mode

哇喔🎉!目前为止我们做得还不错😁。下一步,我们将把它添加action为函数的参数。



function dispatch(action) {

}


Enter fullscreen mode Exit fullscreen mode

因此,我们知道,当调用 dispatch 函数时,它会被传递一个 action 对象作为参数。如果您使用useReduceruseDispatch,您已经知道这一点。当 UI 中发生某种事件时,(而不是 Redux 库)会像这样调用 dispatch 函数:dispatch({ type: 'ACTION_TYPE' })。如果您同时使用 Redux 和connect函数,那么这部分内容也会从您的视图中抽象出来,而是由 Redux 库调用 dispatch 函数。我们将在最后详细讨论这一点。让我们继续吧。

现在我们需要进行一些检查。我们需要确保传入的 action 对象是一个对象,并且它有一个type属性。如果其中一个不成立,我们就会抛出一个错误。编写 Reducer 函数时,它会假定这两个条件都成立。



function dispatch(action) {
  // check that the action argument is an object
  if (typeof action !== 'object' || obj === null) {
    throw new Error('actions must be plain object.');
  }

  // check that the action object has a 'type' property
  if (typeof action.type === 'undefined') {
    throw new Error('Actions may not have an undefined "type" property.'
  }
}


Enter fullscreen mode Exit fullscreen mode

很好。现在我们可以放心地构建我们的 Reducer 了,因为我们知道任何被调度的 Action 都是一个对象,并且具有一个 type 属性。

现在到了激动人心的部分!接下来我们要做的就是在 dispatch 函数中调用 reducer 。这是一个抽象部分,它隐藏了我们无法看到幕后发生的事情。不过,在开始写这段代码之前,我们需要先了解几点。

dispatch 函数的作用域与应用的当前状态相同。这意味着在 dispatch 函数内部,我们可以访问一个名为 的对象,currentState该对象代表了应用的当前状态。

我们编写并传入createStore或 的Reducer 函数也处于同一作用域内useReducer。因此,dispatch 函数也可以访问reducer我们传入的 Reducer 函数(无论我们怎么称呼它)。这意味着 dispatch 函数可以调用 Reducer 函数。

这是一个非常简化的版本:



const createStore = () => { 
  // 😮 yep, it’s createStore! But that’s for another article… 

  // state will be initialized then stored here
  const currentState = {};

  // your reducer, or combined reducers, will be accessible here
  const reducer = null;

  // dispatch function in the same scope will have access to the most current state and your reducer(s)
  const dispatch = (action) => {
    // … all the codes
  }


Enter fullscreen mode Exit fullscreen mode

🤯 我知道,我知道……看看它的底层实现,是不是很酷?函数和对象。欢迎来到 JavaScript 函数式编程!一旦你看到它这样写出来,一切就开始变得清晰起来了!但还有更多东西需要探索。

让我们思考一下迄今为止所学到的一切,并将这些新知识与我们对减速器的了解结合起来。

  • dispatch可以访问currentStatereducer
  • dispatch被调用时,它会接收一个动作对象作为参数。
  • Reducer 函数在调用时会传递两个参数 - state(表示当前状态)和action。明白我的意思了吧?

dispatch我们现在将在里面调用reducer并传入currentState对象action



function dispatch(action) {
  // check that the action argument is an object
  if (typeof action !== 'object' || obj === null) {
    throw new Error('actions must be plain object.');
  }

  // check that the action object has a 'type' property
  if (typeof action.type === 'undefined') {
    throw new Error('Actions may not have an undefined "type" property.');
  }

  // call the reducer and pass in currentState and action
  // reducer and currentState are within scope, action is the parameter passed into the function
  reducer(currentState, action);
}


Enter fullscreen mode Exit fullscreen mode

仔细看看……当一个动作被调度时,或者换句话说,当我们调用dispatch并传入一个动作对象时,dispatch函数会调用我们的 reducer 并传入当前状态和动作对象!🤩 一切都开始有意义了!

好了,还有最后一部分——更新状态。想想你是怎么写一个 Reducer 函数的。它返回什么?它会返回一个新的状态对象,对吧?你遵循了不可变原则,返回的是旧状态的副本,并根据你之前调度的 Action 更新了新数据。所以,当函数dispatch执行这个操作时——reducer(currentState, action);那个函数调用会返回一个全新的状态对象。我们这里的调度函数需要用调用 Reducer 返回的新状态对象来更新 currentState。



function dispatch(action) {
  // check that the action argument is an object
  if (typeof action !== 'object' || obj === null) {
    throw new Error('actions must be plain object.');
  }

  // check that the action object has a 'type' property
  if (typeof action.type === 'undefined') {
    throw new Error('Actions may not have an undefined "type" property.');
  }

  // call the reducer and pass in currentState and action
  // capture the new state object in currentState, thus updating the state
  currentState = reducer(currentState, action);
}


Enter fullscreen mode Exit fullscreen mode

瞧!我们已经构建了该dispatch函数的简单实现。当然,实际实现中还有更多内容。在 Redux 中,dispatch需要告知应用程序状态已更新。这通过监听器和订阅来实现。在钩子中,React 识别到状态已更新并重新渲染组件。更新后的状态随后返回到调用钩子useReducer的组件。useReducer

无论额外的实现如何,在这里构建函数将真正帮助我们了解从组件dispatch调用时幕后发生的情况。dispatch

Redux 和 action creators

如果您正在使用 Redux 和connect,则还有一层抽象需要探索。使用connect函数时,您可以将 Action Creator 传递给函数中的一个对象connect。然后,Action Creator 会通过 props 传递给组件。在您的组件中,当您调用 Action Creator 时,它会为您调用 dispatch 方法。这就是新增的抽象层。让我们看看connect底层是如何运作的(同样是简化版)。



// inside the connect function implementation
dispatch(actionCreator());


Enter fullscreen mode Exit fullscreen mode

因此,将函数connect包装在动作创建器调用周围。当动作创建器被调用时,它会返回一个动作。因此,上述代码的计算结果如下:dispatch



dispatch({ type: 'ACTION_TYPE' });


Enter fullscreen mode Exit fullscreen mode

现在我们知道它会调用 Reducer 了!哇哦!🚀

结论

希望这能帮助你消除 Reducer 和 Dispatch 的黑魔法!如果你仔细思考一下逻辑流程,就会发现这其实就是函数调用函数并传递数据。现在 Redux 的黑魔法已经被稍微清除了,你可以回到使用 React 和 Redux 构建 Web 应用的乐趣中了⚛️!

鏂囩珷鏉ユ簮锛�https://dev.to/dustinmyers/what-even-is-a-dispatch-function-27ma
PREV
使用 React 16.5 分析器加快渲染速度
NEXT
构建 Visual Studio Code 扩展以从模板生成文件