在以下情况下,我想知道如何不突变状态:
我正在使用React Hooks。我有一个列出TodoList
的{{1}}。可以单击TodoItems
来运行一个名为TodoItems
的函数,该函数可以切换其toggle
属性。
completed
有人告诉我这是变异状态:
您创建了todos数组的副本,但是仍然对数组中的项进行了变异:
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} /> ))} </> ); }
散布数组只会创建该数组的浅表副本,但是原始的todo对象不会被复制并因此发生变异。
那么,在不改变状态的情况下处理此问题的正确方法是什么?我尝试传递newTodos[index].completed = !newTodos[index].completed;
参数,但是状态不会更新:
prevTodos
更新:我查看了您所有推荐的帖子。这是一个解决方案,尽管我想知道是否有一种更简洁的表达方式:
const toggle = index => {
setTodos(prevTodos => {
prevTodos[index].completed = !prevTodos[index].completed;
return prevTodos;
});
};
更新2:谢谢大家。我在下面发布了解决方案。 StackOverflow不允许我接受2天,但是我会做。在建议的帖子上接受的答案建议使用第三方库,并且不使用React Hooks,因此我不认为这个问题是重复的。
答案 0 :(得分:0)
找到了解决方案。 map
将返回一个不同的数组,您可以侦听index参数(在下面的代码段中为i
),以侦听当前索引并更改您要定位的对象。>
const toggle = index => {
setTodos(
todos.map((todo, i) =>
i === index ? { ...todo, completed: !todo.completed } : todo
)
);
};
这些线程帮助我将它们拼凑在一起:
感谢所有提供帮助的人。
答案 1 :(得分:0)
是的,避免此问题的最简单方法是avoid mutating data。
做到这一点的一种方法是使用功能性方法,特别是使用.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>
答案 2 :(得分:-3)
const toggle = (index) => {
const oldTodo = todos[index];
setTodos(oldState => {
oldState.splice(index, 1, {...oldTodo, checked: !oldTodo.checked})
return oldState
})
}