【问题标题】:Am I Handling State Updates in this React Hooks Reducer?我是否在这个 React Hooks Reducer 中处理状态更新?
【发布时间】:2019-07-21 20:55:41
【问题描述】:

在下面的代码 sn-p 中,我有一个工作减速器,我认为它是不正确的,因为它重新使用现有状态而不是替换它。它确实有效,但没有任何与我有关的错误。

  1. 不需要 Object.assign 是否正确?
  2. 假设它不正确是否应该出现错误?
  3. 是否有任何工具可以帮助我验证状态更新的正确性?

进入这个 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;

【问题讨论】:

  • 它之所以有效,是因为map 的结果是一个新数组,但你是对的,你不应该改变数组中的对象。从 if 语句返回 { ...item, favorite: item.favorite + 1 } 是可行的方法。
  • 有道理@Tholle 有没有工具可以在我犯这样的错误时警告我?我记得在我使用过的中间件 pre-hook 中有一些东西,但不记得细节了。
  • 我不确定。有一些 Eslint 规则可以帮助against mutating state directly,但我不知道有什么可以警告减速器中的突变。可能是 TypeScript 足够聪明,可以给你一个编译时错误,但我不确定。

标签: reactjs react-redux immutability react-hooks


【解决方案1】:

这对吗?

item 的突变在"favorite" 的情况下确实是可疑的,正如@Tholle 指出的那样。 reducer 中的突变通常被认为是一种反模式,并且经常会导致错误。我肯定会建议将其更改为不可变模式。

然后……

假设它不正确,为什么这不会导致错误?

reducer 中的可变性是错误的常见来源,但特定位的突变是否会导致错误取决于它的突变方式以及 reducer 的使用方式。

虽然收藏夹案例可能会错误地将 item 对象从一个状态版本重用到另一个版本,但它总是会生成一个新的状态数组,因为 Array.prototype.map 总是返回一个新数组。因此,例如,只关心外部状态对象身份的useReducer 将正确触发重新渲染,尽管发生了突变。

另一方面,在数组中的特定项目上记忆的 redux 选择器会错误地返回旧值。如果旧的items 被缓存并重用,那么突变也可能在那里导致意外的错误。但这些都是相当具体的情况,所以在大多数情况下,我怀疑这会奏效。 (不过,我仍然会将其更改为不变异)

有什么工具可以帮助我验证状态更新的正确性吗?

您想要的是某种形式的不变性:JS 中有许多用于不变性的库。

  • ImmutableJS 使用自己的 API 定义自己的数据结构
  • seamless-immutable 定义了看起来像普通可变数据结构的不可变数据结构
  • immer 让您可以使用普通的可变操作语法进行不可变操作。

Typescript 也可以单独使用,也可以与这些库结合使用:允许将对象和数组声明为只读,如果您对它们进行变异,则会引发编译器错误。

linter 规则也可能有帮助,但它会很棘手,除非您可以禁止整个代码库中的所有突变,或者手动切换内部 reducer 的规则。

【讨论】:

    猜你喜欢
    • 2021-03-29
    • 1970-01-01
    • 2019-08-08
    • 1970-01-01
    • 2023-03-16
    • 2020-11-15
    • 2021-01-08
    • 1970-01-01
    • 2020-12-28
    相关资源
    最近更新 更多