我正在重构一个React / Redux应用程序,该应用程序已构建到需要去重化许多reducer逻辑的地步。我已经研究了High Order Reducers,但我很难把头放在如何使它们为我服务上。

这是一个例子:

reducers.js

import components from './entities/components';
import events from './entities/events';
import items from './entities/items';

const entities = combineReducers({
  components,
  items,
  events,
});

我正在使用normalizr。这是我的状态的一个想法。对于此示例,只知道事件可以属于组件或项目,但是在其他方面两者是可区分的。
{
  entities: {
    components: {
      component_1: {
        events: ['event_1'],
      },
    },
    items: {
      item_1: {
        events: ['event_2'],
      },
    },
    events: {
      event_1: {
        comment:  "foo"
      },
      event_2: {
        comment:  "bar"
      }
    }
  }
}

我在所有3个reducer中都使用了EVENT_ADD操作类型。 component.js item.js (在下面)的逻辑是相同的,但是两者还具有针对其类型的独立操作。

在这里,我通过使用Immutable.js的.has()函数检查目标ID是否在该状态的一部分中,从而不必要地将事件添加到了错误的位置。
export default (state = getInitState('component'), action) => {
  switch (action.type) {
    case EVENT_ADD:
      return state.has(action.targetId) ?
        state.updateIn(
          [action.targetId, 'events'],
          arr => arr.push(action.event.id)
        ) :
        state;

    [...]
  }
}

event.js 中,我也在这里使用EVENT_ADD将事件的内容添加到该状态的该部分。
export default (state = getInitState('events'), action) => {
  switch (action.type) {
    case EVENT_ADD:
      return state.set(action.event.id, fromJS(action.event));

    [...]
  }
}

我对高阶 reducer 的理解是,我需要执行以下一项或两项操作:
  • 使用单独的操作类型ADD_EVENT_${entity}(因此使我同时使用 event.js 中的EVENT_ADD_COMPONENTEVENT_ADD_ITEM来创建事件,而不管其父级如何。)
  • 在主 reducer 中按名称过滤,如bottom of the docs所示,在这种情况下,如果我只是为两者共享一个 reducer ,则我不确定如何区分我的initialState和特定于组件和项目的 Action 。

  • 似乎我想要一些 sharedReducer.js ,可以在组件和项之间共享逻辑以执行ADD_EVENTDELETE_EVET等操作,然后每个实体还具有两个独立的reducer。我不确定如何才能做到这一点,或者不确定哪种设计模式是最好的。

    任何指导将不胜感激。谢谢!

    最佳答案

    短语“高阶$ THING”通常表示“以$ THING作为参数,并且/或者返回新的$ THING的函数”(其中“$ THING”通常是“function”,“component”,“reducer” ”等)。因此,“高阶缩减器”是一个接受一些参数并返回缩减器的函数。

    在您链接的Structuring Reducers - Reusing Reducer Logic部分中,最常见的高阶化简器示例是一个函数,该函数接受某种区分值,例如ID或操作类型或子字符串,并返回一个新的化简器函数,该函数使用该区分值来了解其实际值。应该回应。这样,您可以创建同一功能的多个实例,即使其余逻辑相同,也只有“正确的”一个实例才能响应给定的操作。

    看来您通常已经走在正确的轨道上,并且有几种方法可以组织共享逻辑。

    一种方法可能是先明确查找“常见”操作并运行该reducer,然后查找特定情况:

    export default (state = getInitState('events'), action) => {
        // First check for common cases
        switch(action.type) {
            case EVENT_ADD:
            case OTHER_COMMON_ACTION: {
                state = sharedReducer(state, action);
                break;
            }
        }
    
        switch(action.type) {
            case EVENT_ADD:
            case EVENTS_SPECIFIC_ACTION: {
                return eventsSpecificReducer(state, action);
            }
        }
    
        return state;
    }
    

    另一种方法可能是使用类似 reduce-reducers 实用程序的工具,如Structuring Reducers - Beyond combineReducers 部分所示:
    const entities = combineReducers({
        components : reduceReducers(componentsReducer, sharedReducer),
        items : reduceReducers(itemsReducer, sharedReducer)
        events,
    });
    

    希望这能为您指明正确的方向。如果您还有其他问题,请随时在这里提问,或在Discord的Reactiflux聊天 channel 中-邀请链接位于https://www.reactiflux.com。 (注意:我是Redux的维护者,"Structuring Reducers" docs section的作者,并且是Reactiflux的管理员。)

    10-05 20:35
    查看更多