本文介绍了Redux - 在中间件中调用 storeAPI.disapatch(action) 会导致“递归过多"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习 Redux 基础教程.在 '编写自定义中间件',我们了解到中间件被编写为一系列三个嵌套函数,如下所示:

I'm working through the Redux fundamentals tutorial. In the section on 'Writing Custom Middleware', we learn that middleware are written as a series of three nested functions like so:

// Outer function:
function exampleMiddleware(storeAPI) {
  return function wrapDispatch(next) {
    return function handleAction(action) {
      // Do anything here: pass the action onwards with next(action),
      // or restart the pipeline with storeAPI.dispatch(action)
      // Can also use storeAPI.getState() here

      return next(action)
    }
  }
}

exampleMiddleware 解释如下:

exampleMiddleware:外部函数实际上是中间件"本身.它会被 applyMiddleware 调用,并且 接收一个 storeAPI包含商店的 {dispatch, getState} 函数的对象.这些实际上是相同的 dispatch 和 getState 函数商店.如果你调用这个 dispatch 函数,它会发送 action到中间件管道的开始.这仅被调用一次.

我不明白倒数第二句话是什么意思(如果你调用这个dispatch函数,它会将动作发送到中间件管道的开头),所以我尝试调用store.dispatch(action) 位于示例应用程序的 src/exampleAddons/middleware.js 中提供的中间件之一中,以查看会发生什么并递归过多".这是演示.

I didn't understand what was meant by the second last sentence (If you call this dispatch function, it will send the action to the start of the middleware pipeline), so I tried calling store.dispatch(action) inside one of the middlewares provided in src/exampleAddons/middleware.js of the example app to see what happens and got "too much recursion". Here's the demo.

所以storeAPI.dispatch()是所有中间件组合起来的composed调度函数,而不是原来store的dispatch,这就解释了递归.但是storeAPI.dispatch()有什么用?我是否使用不当?

So storeAPI.dispatch() is the composed dispatch function of all the middlewares combined rather than the original store's dispatch, which would explain the recursion. But then what is the use of storeAPI.dispatch()? Am I using it incorrectly?

applyMiddleware来源:

function applyMiddleware(...middlewares) {
  return createStore => (...args) => {
    // ...1) createStore is called and the resulting store is saved as `store`
    const store = createStore(...args)
    
    // ...2) a `dispatch` variable is defined and assigned some function
    let dispatch = () => {
      throw new Error(
        'Dispatching while constructing your middleware is not allowed. ' +
          'Other middleware would not be applied to this dispatch.'
      )
    }
    
    // ...3) a middlewareAPI object is defined containing the store's getState method and the `dispatch` function from 2).
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    
    // ...4) the middlewares passed to applyMiddleware are called with the `middlewareAPI` object from 3) and the resulting functions are saved in array `chain`.
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    
    // ...5) the middlewares are composed and the resulting "composed" middleware function is called with `store.dispatch`. 
    // This returns a composed dispatch function that chains together the `handleAction` functions of all the middlewares passed to applyMiddleware. 
    // This composed dispatch gets assigned to the `dispatch` variable from 2). 
    // Since the `storeAPI.dispatch` is referencing this variable, calling `storeAPI.dispatch` now calls the composed middleware function, which causes the infinite loop. 
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

无限循环似乎是上面注释中第5步重新赋值的结果.但我不确定我的推理是否正确,或者我是否正确使用了 storeAPI.dispatch.我很感激社区可以在这里提供的任何指导,因为我找不到任何调用 storeAPI.dispatch() 的中间件示例.

The infinite loop seems to be the result of the re-assignment at step 5 in the annotations above. But I'm not sure if my reasoning is correct or if I'm even using storeAPI.dispatch correctly. I would appreciate any guidance the community could provide here as I wasn't able to find any examples of middleware that call storeAPI.dispatch().

推荐答案

是的,在中间件中调用 storeAPI.dispatch() 会将操作发送到中间件管道的最开始.这意味着如果我们有中间件 a->b->c->store,并且 b 调用 storeAPI.dispatch({type: "some/action"}),中间件 b 几乎会立即看到完全相同的 action 对象.

Yes, calling storeAPI.dispatch() in a middleware sends the action to the very start of the middleware pipeline. That means that if we have middlewares a->b->c->store, and b calls storeAPI.dispatch({type: "some/action"}), middleware b will see that exact same action object go through almost immediately.

因此,中间件永远不应该无条件地调用 storeAPI.dispatch(),因为那导致无限循环!这基本上是与在 React 组件 useEffect 钩子中无条件调用 setState() 一样的问题.效果在渲染后运行,并且 setState() 将另一个渲染排队,所以如果你每次都设置状态,你总是强制重新渲染,这是一个无限循环.这里也一样.

Because of that, a middleware should never call storeAPI.dispatch() unconditionally, because that will cause infinite loops! This is basically the same problem as something like calling setState() unconditionally in a React component useEffect hook. The effect runs after rendering, and setState() queues up another render, so if you always set state every time, you always force a re-render, and that's an infinite loop. Same thing here.

因此,在中间件中对 storeAPI.dispatch() 的任何使用都应该包含在条件检查中,以便它只在某些时间发生,而不是所有时间.

So, any use of storeAPI.dispatch() in a middleware should be wrapped in a conditional check so that it only happens some of the time, not all of the time.

这篇关于Redux - 在中间件中调用 storeAPI.disapatch(action) 会导致“递归过多"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-02 07:28