使用选择器计算来自 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)。
- 记忆也需要额外的内存。
假设我有一个音乐商店应用程序,用户可以在其中搜索吉他。在初始页面加载时,我获取了几种吉他来显示:(原声、电和贝斯)。吉他结果页面从单个 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)。 - 记忆也需要额外的内存。