如何在不改变数组的情况下更新此状态?



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

我正在使用 React Hooks。我有一个列出TodoItemsTodoList. 可以单击TodoItems以运行名为toggle的函数,该函数切换其completed属性。

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,所以我不认为这个问题是重复的。

没错,避免此问题的最简单方法是避免更改数据。

一种方法是使用函数式方法,特别是使用非变异数组方法,如.map

function TodoList() {
const [todos, setTodos] = React.useState([{
text: "Example",
completed: true
}]);
const toggle = index => {
const updatedTodos = todos.map((todo, i) => {
if (i === index) {
todo.completed = !todo.completed;
}
return todo;
});
setTodos(updatedTodos);
};
return (
<React.Fragment > 
{todos.map((item, index) => (
<p
key={item.text}
onClick={() => toggle(index)}
className={item.completed ? "completed" : ""}
>
{item.text}
</p>
))}
</React.Fragment>
);
}
ReactDOM.render( < TodoList / > , document.getElementById('root'))
.completed {
text-decoration: line-through;
}
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"></div>

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

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

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

  • 如果我使用点差运算符,为什么状态会发生变化?
  • 在 ReactJS 中更新数组中对象的最佳方法是什么?

感谢所有提供帮助的人。

const toggle = (index) => {
const oldTodo = todos[index];
setTodos(oldState => {
oldState.splice(index, 1, {...oldTodo, checked: !oldTodo.checked})
return oldState
})
}

相关内容

  • 没有找到相关文章

最新更新