Redux - 在中间件中调用 storeAPI.disapatch(action) 会导致“递归过多" [英] Redux - Calling storeAPI.disapatch(action) inside middleware causes 'too much recursion'

查看:42
本文介绍了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到中间件管道的开始.这仅被调用一次.

exampleMiddleware: The outer function is actually the "middleware" itself. It will be called by applyMiddleware, and receives a storeAPI object containing the store's {dispatch, getState} functions. These are the same dispatch and getState functions that are actually part of the store. If you call this dispatch function, it will send the action to the start of the middleware pipeline. This is only called once.

我不明白倒数第二句话是什么意思(如果你调用这个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) 会导致“递归过多"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆