首页 > 解决方案 > 如何在不改变数组的情况下更新此状态?

问题描述

我想知道如何在以下情况下不改变状态:

我正在使用 React Hooks。我有一个TodoList列表TodoItemsTodoItems可以单击以运行一个调用togglecompleted属性的函数。

import React, { useState } from "react";
import TodoItem from "./TodoItem";

export default function TodoList() {
  const [todos, setTodos] = useState([
    { text: "Example", completed: false }
  ]);

  const toggle = index => {
    const newTodos = [...todos];
    newTodos[index].completed = !newTodos[index].completed; // Mutating state?
    setTodos(newTodos);
  };

  return (
    <>
      {todos.map((item, index) => (
        <TodoItem key={index} index={index} todo={item} toggle={toggle} />
      ))}
    </>
  );
}

有人告诉我这是变异状态:

你创建了一个 todos 数组的副本,但你仍然改变了数组中的一个项目:

newTodos[index].completed = !newTodos[index].completed;

扩展数组只会创建数组的浅表副本,但原始 todo 对象不会被复制,因此会发生变异。

那么,在不改变状态的情况下处理这个问题的正确方法是什么?我试过传入一个prevTodos参数,但是状态没有更新:

const toggle = index => {
  setTodos(prevTodos => {
    prevTodos[index].completed = !prevTodos[index].completed;
    return prevTodos;
  });
};

更新:我看过你们都推荐的帖子。这是一个解决方案,尽管我想知道是否有更简洁的方式来表达它:

const toggle = index => {
  setTodos(
    todos.map((todo, i) =>
      i === index ? { ...todo, completed: !todo.completed } : todo
    )
  );
};

更新2:谢谢大家。我在下面发布了解决方案。StackOverflow 不会让我接受它 2 天,但我会这样做。建议帖子上接受的答案建议使用第三方库,并且它不使用 React Hooks,所以我不认为这个问题是重复的。

标签: javascriptreactjsreact-hooks

解决方案


找到了解决方案。map将返回一个不同的数组,您可以收听 index 参数(在下面的代码段中,这是i)来收听当前索引并更改您的目标对象。

const toggle = index => {
  setTodos(
    todos.map((todo, i) =>
      i === index ? { ...todo, completed: !todo.completed } : todo
    )
  );
};

这些线程帮助我将其拼凑在一起:

感谢所有帮助过的人。


推荐阅读