拆分依赖减少者

时间:2016-06-21 09:00:03

标签: events reactjs redux react-redux reducers

我的问题是关于如何组织我的减速器。

让我们说我的状态是这样的:

resources: [
    {
        id: 1,
        name: "John", 
        /* ... 100 more properties ... */
    }, 
    {
        id: 1,
        name: "Daniel", 
        /* ... 100 more properties ... */
    }, 
]
events: {
    planned: [
        {
            resourceId: 1, 
            name: "Concert with Adele", 
            /* ... 100 more properties ... */
        }
    ]
}

首先,我们假设我们有一台减速机。业务逻辑是这样的:

  1. 可以随时添加和删除资源。
  2. 如果没有资源的事件,第一个资源将被添加到事件中。
  3. 如果有资源的事件并且资源被删除且没有其他资源,则将取消设置resourceId。
  4. 如果有资源的事件并且资源被删除且有其他资源,则resourceId将被设置为剩余资源中的第一个。
  5. 有很多逻辑可以处理"资源"状态树的分支,同时有很多逻辑来处理事件"状态树的一部分。

    点2,3和4引入了资源"之间的依赖关系。和"事件",我试图以最好的方式解决。

    天真的解决方案

    天真的解决方案是让一个减速器来处理所有动作。这样,当删除资源时,我们可以简单地删除资源,检查是否还有其他资源,然后相应地更新事件。但是,保持“资源”的逻辑。和'事件'在一起,只是因为这感觉不好。

    维护自己的列表

    另一种替代方法是将资源和事件的处理拆分为两个不同的reducer。在状态树的Events部分,我们可以保留一个可用的resourceId列表,以便我们知道如何更新我们的事件。我们仍然可以监听与资源缩减器相同的事件,但只保存相关数据。像

    这样的东西
    resources: [
        {
            id: 1,
            name: "John", 
            /* ... 100 more properties ... */
        }, 
        {
            id: 2,
            name: "Daniel", 
            /* ... 100 more properties ... */
        }, 
    ]
    events: {
        resourceIds: [1,2], /* ADDED: Keeping track of available resources */
        planned: [
            {
                resourceId: 1, 
                name: "Concert with Adele", 
                /* ... 100 more properties ... */
            }
        ]
    }
    

    代理操作

    第三个选项是为REMOVE_RESOURCE操作创建一个侦听器(例如redux-saga),然后触发另一个包含当前默认资源ID的操作UPDATE_DEFAULT_RESOURCE_ID。

    对这里正确的做法有什么想法?

2 个答案:

答案 0 :(得分:0)

我个人喜欢在ducks中拆分我的代码,并使用您在选项2中所述的规范化状态。每当我需要执行涉及两个或更多缩减器的复杂逻辑时,我使用redux-saga正如你在第三个选项中提到的那样。

这样做我保持" inter redurs"逻辑分离,更容易通过传奇测试。此外,您最终无法使用duck circle

The so called Duck Circle !

一般来说,当你看到圈子依赖时,它通常是设计不佳的强烈信号。

答案 1 :(得分:0)

链缩减器,以便更新事件的操作使用资源缩减器,它在保持依赖关系的同时分离两者的关注点。

event_reducer(state, action) {
  switch(action.type) {
    case 'REMOVE_RESOURCE_FROM_EVENT':
      return {...state, resource_id: resource_reducer(null, action)}
  }
}

resource_reducer(state, action) {
  switch (action.type) {
    case 'REMOVE_RESOURCE_FROM_EVENT':
      let id = null;
      if (resources.length > 0) {
         id = resources[0].id;
         resources = resources.slice(1);
      }
      return id;
  }
}