避免导入订单/ cirulcar依赖性错误,多个Reducer在Redux中监听相同的操作

时间:2016-06-24 15:01:50

标签: javascript import redux

我一直在使用看似非常常见的“模块”模式的Redux项目,其中负责单个状态切片的操作,操作创建者和操作处理程序组合在一个文件中,并且这些文件导出的reducer通过combineReducers合并为一个根reducer。

我一直在使用这种模式取得了一些成功,但是当我尝试让模块监听其他模块导出的动作时,我遇到了一些非常微妙和烦人的错误。

第一次遇到问题时,模块A从模块B导入动作,模块B从模块A导入动作,创建循环依赖。很好,可以理解,我可以解决这些问题。

但是我也遇到过这样的情况:只是从模块B中的模块A导入一个动作导致该动作未定义 - 我假设基于combineReducers导入或消化模块的顺序,尽管我没有我确切地知道了(即使在rootReducer文件中模块B之前导入模块A时,有时也会发生这种情况)。

所以我的问题是:在多个减速器中听同样的动作被认为是一个好的模式,还是应该避免的?这似乎是Redux做事方式的鼓舞,但我可能会遗漏一些东西。

为了给出一个人为的例子,假设我想在我的应用程序中保留某些操作的运行日志。所以我有一个“日志”模块,它可以监听所需的操作并根据需要更新其状态片段。

假设我有一个用户模块,它开始于:

export const ADD_USER = 'ADD_USER';

export function addUser (user) {
  return {
    type: ADD_USER,
    user: user
  }
};

然后,如果我想在添加新用户时记录,我可能会执行以下操作:

   import { ADD_USER } from './users';

   const ACTION_HANDLERS = {
    [ADD_USER]: (state, action) => {
       return [
         ...state,
         'Added user: ' + action.user.name
       ];
     }
   }
   const initialState = []
   export default function logReducer (state = initialState, action) {
      const handler = ACTION_HANDLERS[action.type]
      return handler ? handler(state, action) : state
   }

大多数情况下,这种方法运行良好。但有时ADD_USER在导入时将是未定义的,因此动作处理程序将(安静地)错过该动作。非常讨厌!

如果这确实是要走的路,我应该如何避免这些错误?显而易见的解决方案似乎是将动作consts放在一个在所有模块之前导入的actions.js文件中,但这似乎打败了模块化点。另一种选择是编写动作处理程序,如:

ADD_USER: (state, action) => {}

在听“外国”行动时。但是为什么要将它们定义并导出为常量?

1 个答案:

答案 0 :(得分:2)

是的,Redux绝对鼓励多个Reducer响应相同的操作。这就是典型的基本Redux文件结构确实具有动作常量的单独文件的原因 - 它们可以由多个单独的reducer文件导入,也可能是单独的动作创建器文件。

“ducks”或“modules”结构 在某种程度上很受欢迎,当然也是组织代码的有效方法,但也基于只有一组reducer会响应a给予行动。虽然“ducks”规范确实建议从模块中导出动作常量,但暗示你实际上不会有这些相互依赖,因为没有其他模块会/应该关心另一个模块中发生了什么。

对于它的价值,Redux的创造者Dan Abramov非常支持处理相同行为的任意减速器,并且通常不同意“鸭子”方法。显然只有一种观点,你绝对可以自由地做任何最适合你自己应用的事情,但需要考虑的事情。

最终,我认为答案是你试图使用“模块化”方法,但发现所需行为确实不是“模块化”的。