Redux 我可以在单独的减速器中使用一种动作类型吗?

Posted

技术标签:

【中文标题】Redux 我可以在单独的减速器中使用一种动作类型吗?【英文标题】:Redux can I use one action type in separate reducers? 【发布时间】:2017-03-24 15:52:59 【问题描述】:

在我的 Redux 应用程序中,我目前有 3 个独立的 reducer 处理从 api 获取数据的情况。我的一个减速器的一个例子是:

const INITIAL_STATE = 
  data: [],
  loading: false,
  error: ''
;

export default (state = INITIAL_STATE, action) => 
  switch (action.type) 
    case GET_ALL_ORDERS_START:
      return 
        ...state,
        loading: true
      ;
    case GET_ALL_ORDERS_SUCCESS:
      return 
        ...state,
        allOrders: action.payload,
        loading: false
      ;
    case GET_ALL_ORDERS_FAIL:
      return 
        ...state,
        loading: false,
        error: action.payload
      ;
    default:
      return state;
  
;

注意加载和错误状态,这些在每个当前的 reducer 中都是相同的,并且将适用于我编写的涉及从 api 获取数据的任何后续 reducer。

我想添加一个仅用于加载和错误状态的reducer。其他 3 个将存储数据。

这会给我:

数据缩减器 x 3

const INITIAL_STATE = 
  data: []
  // any other state in the future
;

export default (state = INITIAL_STATE, action) => 
  switch (action.type) 
    case GET_ALL_ORDERS_SUCCESS:
      return 
        ...state,
        allOrders: action.payload
      ;
    default:
      return state;
  
;

加载/错误减少器(处理整个应用程序的加载/错误)

const INITIAL_STATE = 
  loading: false,
  error: ''
;

export default (state = INITIAL_STATE, action) => 
  switch (action.type) 
    case GET_ALL_ORDERS_START:
      return 
        ...state,
        loading: true
      ;
    case GET_ALL_ORDERS_SUCCESS:
      return 
        ...state,
        loading: false
      ;
    case GET_ALL_ORDERS_FAIL:
      return 
        ...state,
        loading: false,
        error: action.payload
      ;
    default:
      return state;
  
;

如您所见,这意味着 GET_ALL_ORDER_SUCCESS 操作类型将在 2 个单独的减速器中使用。我的问题是,这样可以吗?还是违反惯例?

非常感谢。

【问题讨论】:

在 redux 风格指南中强烈建议这样做。这是链接redux.js.org/style-guide/… 【参考方案1】:

我认为这很好。没有地方说明 Actions 和 Reducers 具有 1:1 的映射关系。事实上,Redux 的创建者明确表示它们之间没有任何关系,许多 reducer 可以对单个动作做出反应,单个 reducer 可以对多个动作做出反应。

我认为他说得最好:https://github.com/reduxible/reduxible/issues/8

推文:https://twitter.com/dan_abramov/status/691608868628119552

相关SO:Redux: Why not put actions and reducer in same file?

【讨论】:

谢谢@julianljk 我已经实施了这个解决方案,它似乎工作得很好,但我只是想澄清一下,它不会在稍后阶段咬我@£$。 有一个折衷方案,一个完成所有事情的单一操作不太明确且更难调试(如果您关心日志记录)。其中多个动作更明确。我认为这是为了找到平衡 当然。另请参阅 redux.js.org/docs/faq/Actions.html#actions-reducer-mappings 和 redux.js.org/docs/recipes/StructuringReducers.html 了解有关该主题的更多详细信息。 但是如何使用 redux'x bindActionCreators 来调度两个 reducer 函数以响应单个操作? 一个动作触发多个reducer有助于防止每个reducer代码膨胀。将每个动作关注点隔离在它自己的减速器中。 IE:UPDATE_USER 可能会触发多个reducer 来更新用户对象、权限、计费等。【参考方案2】:

如果我可以在两个或多个单独的减速器中使用相同的动作类型名称,我有一个类似的问题,如果没有非常特殊的情况,答案肯定是否定的。

为什么不呢?

即使我们在 dispatch action 时通过 combineReducers 函数组合它们之后单独编写 reducer,所有 reducer 都被称为它们的 switch case 语句。

减速机一:

export const postReducer = (state = INITIAL_STATE, action) => 
  switch (action.type) 
    case "SET_DATA":
      const  posts  = action.payload;
      return 
        ...state,
        posts: posts,
      ;
  
;

减速机二:

export const commentReducer = (state = INITIAL_STATE, action) => 
  switch (action.type) 
    case "SET_DATA":
      const  comments  = action.payload;
      return 
        ...state,
        comments: comments,
      ;
  
;

所以当我们派发一个 SET_DATA 类型的动作时,两个 reducer 都会被调用 如果有效载荷值为


  comments: ['comment one', 'comment two'] 

post reducer 会将其帖子设置为未定义。

更好的解决方案是这样命名类型:

case "SET_POST_DATA":

case "SET_COMMENT_DATA": 

避免两个reducer的动作发生冲突。

约定是,当调用 action 时,只有一个 reducer 负责回答该 action,否则可能会引起其他开发人员的误解

【讨论】:

以上是关于Redux 我可以在单独的减速器中使用一种动作类型吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用通用动作和减速器简化 redux

我的减速机应该处理@@ redux-saga-test-plan / INIT动作吗?

Redux - reducer 与动作的关系

Redux减速器工厂类型问题中的Typescript映射类型

在 react redux 中全局状态更改后调度新动作

跨多个 React 应用共享 redux 服务层