我在这个 React Hooks Reducer 中处理状态更新吗?
Am I Handling State Updates in this React Hooks Reducer?
在下面的代码片段中,我有一个工作的减速器,我认为它是不正确的,因为它重新使用现有状态而不是替换它。它确实有效,但没有让我担心的错误。
- 不需要 Object.assign 是否正确?
- 假设不正确应该有错误吗?
- 有什么工具可以帮助我验证状态更新的正确性?
进入这个 reducer 的状态只是一个只有第一级对象的简单数组。也就是说,类似于:
const stateIn = [{id: 101,favorite: 0},{id: 102,favorite: 1},...]
我怀疑的减速器如下:
const speakersReducer = (state, action) => {
switch (action.type) {
case "loadspeakers": {
return action.data;
}
case "favorite": {
return state.map((item, index) => {
if (item.id === action.sessionId) {
// let speakerToUpdate = Object.assign(item);
// speakerToUpdate.favorite = 1;
item.favorite = 1;
return item;
// return speakerToUpdate;
}
return item;
});
}
...
default:
return state;
}
};
export default speakersReducer;
Is this correct?
item
的突变在 "favorite"
案例中确实是可疑的,正如@Tholle 指出的那样。 reducer 中的突变通常被认为是 anti-pattern 并且经常会导致错误。我肯定会建议将其更改为不可变模式。
但后来...
Why doesn't this cause an error, assuming it's not correct?
reducer 中的可变性是错误的常见来源,但特定的突变是否会导致错误取决于它的变异方式以及 reducer 的使用方式。
虽然收藏夹案例可能会错误地将 item
object 从一个状态版本重用到另一个状态,但它总是会产生一个新的状态数组,因为 Array.prototype.map
总是 returns 一个新数组。因此,例如,只关心外部状态 object 的身份的 useReducer
将正确触发 re-render,尽管发生了突变。
另一方面,在数组中的特定项目上记忆的 redux 选择器会错误地 return 旧值。如果旧的 items
被缓存和重用,突变也可能导致意想不到的错误。但这些都是相当具体的案例,所以在大多数情况下,我怀疑这会奏效。 (不过我还是会把它改成不变异)
Any tools that would help me verify correctness for state updates?
你想要的是某种形式的不可变性:在 JS 中有许多用于不可变性的库。
- ImmutableJS 用自己的 API 定义自己的数据结构
- seamless-immutable 定义了看起来像普通可变数据结构的不可变数据结构
- immer 允许您使用普通的可变操作语法执行不可变操作。
此外,Typescript 可以单独使用,也可以与这些库结合使用:允许将 objects 和数组声明为只读,并在更改它们时引发编译器错误。
linter 规则也可能有帮助,但它会很棘手,除非你同意禁止整个代码库中的所有突变,或者手动切换内部 reducer 的规则。
在下面的代码片段中,我有一个工作的减速器,我认为它是不正确的,因为它重新使用现有状态而不是替换它。它确实有效,但没有让我担心的错误。
- 不需要 Object.assign 是否正确?
- 假设不正确应该有错误吗?
- 有什么工具可以帮助我验证状态更新的正确性?
进入这个 reducer 的状态只是一个只有第一级对象的简单数组。也就是说,类似于:
const stateIn = [{id: 101,favorite: 0},{id: 102,favorite: 1},...]
我怀疑的减速器如下:
const speakersReducer = (state, action) => {
switch (action.type) {
case "loadspeakers": {
return action.data;
}
case "favorite": {
return state.map((item, index) => {
if (item.id === action.sessionId) {
// let speakerToUpdate = Object.assign(item);
// speakerToUpdate.favorite = 1;
item.favorite = 1;
return item;
// return speakerToUpdate;
}
return item;
});
}
...
default:
return state;
}
};
export default speakersReducer;
Is this correct?
item
的突变在 "favorite"
案例中确实是可疑的,正如@Tholle 指出的那样。 reducer 中的突变通常被认为是 anti-pattern 并且经常会导致错误。我肯定会建议将其更改为不可变模式。
但后来...
Why doesn't this cause an error, assuming it's not correct?
reducer 中的可变性是错误的常见来源,但特定的突变是否会导致错误取决于它的变异方式以及 reducer 的使用方式。
虽然收藏夹案例可能会错误地将 item
object 从一个状态版本重用到另一个状态,但它总是会产生一个新的状态数组,因为 Array.prototype.map
总是 returns 一个新数组。因此,例如,只关心外部状态 object 的身份的 useReducer
将正确触发 re-render,尽管发生了突变。
另一方面,在数组中的特定项目上记忆的 redux 选择器会错误地 return 旧值。如果旧的 items
被缓存和重用,突变也可能导致意想不到的错误。但这些都是相当具体的案例,所以在大多数情况下,我怀疑这会奏效。 (不过我还是会把它改成不变异)
Any tools that would help me verify correctness for state updates?
你想要的是某种形式的不可变性:在 JS 中有许多用于不可变性的库。
- ImmutableJS 用自己的 API 定义自己的数据结构
- seamless-immutable 定义了看起来像普通可变数据结构的不可变数据结构
- immer 允许您使用普通的可变操作语法执行不可变操作。
此外,Typescript 可以单独使用,也可以与这些库结合使用:允许将 objects 和数组声明为只读,并在更改它们时引发编译器错误。
linter 规则也可能有帮助,但它会很棘手,除非你同意禁止整个代码库中的所有突变,或者手动切换内部 reducer 的规则。