2016-06-24 27 views
1

我一直在使用什么似乎是一个非常常见的“模块”模式工作的Redux项目,其中的行动,行动创造者和负责单个状态片的动作处理程序在一个文件中组合在一起,并且从这些文件导出的缩减器通过combineReducers合并到一个单一的根缩减器中。避免进口订单/ cirulcar相关性错误与多个减速器在Redux中监听相同的动作

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

第一次遇到问题时,出现了这样的情况:模块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在导入的时候是未定义的,所以动作处理器会(悄悄地)错过这个动作。很烦人!

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

ADD_USER: (state, action) => {} 

在听“洋”行动,但为什么定义,并将其导出为在所有的常量

回答

2

是的,终极版绝对是鼓励有这就是为什么典型的基本Redux文件结构确实会有单独的文件用于动作常量 - 它们可以由多个单独的reducer文件导入,并且可能还有单独的动作创建器文件。 “鸭子”或“模块”结构有些受欢迎,当然也是组织代码的一种有效方法,但也基于只有一组减速器会响应给定动作的想法。虽然“鸭子”规范确实建议从模块中导出动作常量,但其含义是,实际上不会有这些相互依赖关系,因为没有其他模块会/应该关心另一个模块中正在发生的事情。

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

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

+1

这很有道理,谢谢。我也发现了这一点,解释了Dan Abramov的观点,这对任何遇到我的问题的人都有帮助:http://stackoverflow.com/a/37116923/5059128 –