使用选择器计算来自 API 调用的派生数据是否会比在 reducer 中执行的更好? (对于这个用例)

Will using selectors to compute derived data from an API call perform better than doing within the reducer? (for this use-case)

假设我有一个音乐商店应用程序,用户可以在其中搜索吉他。在初始页面加载时,我获取了几种吉他来显示:(原声、电和贝斯)。吉他结果页面从单个 API 调用一起返回,但永远不会一起显示。因此,必须在某些时候过滤它们。要查看不同类别的吉他,用户将切换他们从 React 组件查看的类别。

似乎有两种主要方法可以解决不可变和 redux 的问题。

在策略一中,我在category上的数据到达时进行过滤,单独存储在redux store中。当我要检索数据时,我在选择器中指定类别。

在策略 2 中,所有进入的 API 数据都存储在聚合列表 "all" 中。当我想检索特定类别的吉他时,我使用选择器从聚合数据中过滤和显示。

策略 1:

// REDUCER
export const GuitarReducer = (state, action) => {
    const { payload, type } = state; 

    switch (type) {
        case "acoustic": {
            let existing = // GET EXISTING
            return state.set("acoustic",
                existing.concat(payload.filter(result => (result.category === "acoustic")))
            )
        }
        case "electric": {
            let existing = // GET EXISTING
            return state.set("electric",
                existing.concat(payload.filter(result => (result.category === "electric")))
            )    
        }
        case "bass": {
            let existing = // GET EXISTING
            return state.set("bass",
                existing.concat(payload.filter(result => (result.category === "bass")))
            )
        }
    }
}

// SELECTOR
export const selectCategory = createSelector(
    [getCategory, getGuitarReducer],
    (category, guitarReducer) => {
        return GuitarReducer.get(category);
    }
);

策略 2:

// REDUCER
export const GuitarReducer = (state, action) => {
    const { payload, type } = state;
    ...
    let existing = // GET EXISTING
    ...
    return state.set("all",
        existing.concat(payload)
    )
}

// SELECTOR
export const selectCategory = createSelector(
    [selectAllGuitars],
    (category, guitars) => {
        return guitars.filter(guitar => (guitar.category = category));
    }
);

一种模式会比另一种模式提供更好的性能吗?哪种模式更好地遵循 redux 的最佳实践?

我听说最好选择选择器来计算派生数据,并且当对数据执行其他操作(例如在选项卡之间切换)时,记忆将缓存结果以供使用。因此,我不清楚该选择哪种策略。

我认为 selectors 主要关注不重新计算组件中的派生数据(以及在其他组件中重用它的好处)。

你的例子中的两个都是很好的做法,所以我会重新构造如下。您希望您的数据存储看起来像选项一还是选项二(原始 API 响应)。你想让它延迟加载(选择二),还是加载所有吉他的类别。

选择 1

优点

  • 以对您的应用程序更有用的格式存储在数据存储中。
  • 选项二在类别更改时重新计算,选项一在开始时计算并且很可能更高效。

缺点

  • 无法访问原始 API 回复。
  • 对 API 请求执行过滤和分类,而不是懒惰地执行(老实说这不是什么大问题)。

选择 2

优点

  • 存储在数据存储原始 API 响应中。
  • 延迟计算所需的吉他类别。

缺点

  • 重新计算类别变化。 (注意 reselect 的缓存大小仅为 1)。
  • 记忆也需要额外的内存。