【问题标题】:Mutable state update in react反应中的可变状态更新
【发布时间】:2020-09-19 17:43:34
【问题描述】:

例如,我们有一个像这样定义的状态,它有一些待办事项,如果这些待办事项已完成,我们想更改该待办事项的完成

this.state = {
  // store an array of todo objects
  todos: [
    { task: 'do the dishes', done: false, id: 1 },
    { task: 'vacuum the floor', done: true, id: 2 }
  ]
};

为此,我们可以做到这一点。

  const theTodo = this.state.todos.find(t => t.id === id);
  theTodo.done = true; // NOOOOO

  this.setState({
    todos: this.state.todos
  });

}

但我有点困惑,数组上的 find 方法将返回与其中条件匹配的元素,我们将其存储在不同的变量中,然后访问完成以将其更改为 true。 但是,我们仍然没有更改原始状态值,因为这是一个副本。

那我们怎么可以用这个来保存呢?

 this.setState({
    todos: this.state.todos // bad
  });

【问题讨论】:

  • 仅仅因为你“将它存储在不同的变量中”,并不意味着它是一个不同的对象,它仍然引用同一个对象。此外,没有什么可以阻止您执行this.setState({ this.state.todos }),但是,这是一种不好的做法,您不应该更改您的state 属性(您的todos 数组,而不是存储在该数组中的objects)。您正在做的事情现在可能有效,但将来可能会中断,因为 React 无法正确处理此类用例。

标签: javascript arrays reactjs react-state-management


【解决方案1】:

代码起作用的原因是因为State Updates are Merged

当您调用setState() 时,React 会将您提供的对象合并到当前状态中

但是,这只是一个不好的做法You shouldn't mutate this.state directly

永远不要直接改变this.state,因为之后调用setState()可能会替换你所做的改变。将 this.state 视为不可变的。

为了完整起见,只需 pass a functionthis.setState 并使用 map 保存不可变规则。

传递更新函数允许您访问更新程序中的当前状态值。

this.setState((prevState) => {
  const todos = prevState.todos.map((todo) =>
    todo.id === id ? { ...todo, done: true } : todo
  );
  return { todos };
});

【讨论】:

  • 顺便说一句,可以改变数组中的对象,但不能改变数组本身,对吗?
  • 它仍然被认为是一种不好的做法,改变数组内的对象仍然可能导致陈旧状态。
  • 你能举个例子吗?
  • 如果你有一个状态[{id:1}]并且你变异了id=2,那么有人可以读取this.state同时相信他得到了id===1
【解决方案2】:

只需spread 一切


this.setState(oldState => {
  const todos = oldState.todos;
  const todoIndex = todos.findIndex(pr => pr.id === id);
  const todo = todos[todoIndex];
  const newTodos = [...todos.slice(0, todoIndex), {...todo, done: true}, ...todos.slice(todoIndex + 1)]

  return {
    ...oldState,
    todos
  }
});

【讨论】:

    【解决方案3】:

    这不是问题或与 React 框架相关的事情。这是对 JavaScript 的基本理解。当然你会得到一个匹配,find 方法适用于任何数组并且你的 todo 是一个数组。 find 方法返回一个新对象而不是对它的引用。如果您只想更新它,请创建您的 todo 的副本,然后使用任何方法更新正确的 todo 项,然后将复制的 todo 添加到新状态。您可以使用 immer,或使用传播运算符,有几种方法可以做到这一点。

    【讨论】:

    • "find 方法返回一个新对象而不是对它的引用,因此返回一个不可变对象。" - 这是一个不正确的说法。它返回它找到的对象,JavaScript 对象在默认情况下不是不可变的,除非你让它们这样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-25
    • 2022-01-23
    • 2018-03-28
    相关资源
    最近更新 更多