[英]How to update state with usestate in an array of objects?
我在使用 React useState 挂钩时遇到了一些问题。 我有一个带有复选框按钮的 todolist,我想将 'done' 属性更新为 'true',它的 id 与 'clicked' 复选框按钮的 id 相同。 如果我 console.log 我的 'toggleDone' function 它会返回正确的 ID。 但我不知道如何更新正确的属性。
当前的 state:
const App = () => {
const [state, setState] = useState({
todos:
[
{
id: 1,
title: 'take out trash',
done: false
},
{
id: 2,
title: 'wife to dinner',
done: false
},
{
id: 3,
title: 'make react app',
done: false
},
]
})
const toggleDone = (id) => {
console.log(id);
}
return (
<div className="App">
<Todos todos={state.todos} toggleDone={toggleDone}/>
</div>
);
}
我想要的更新后的 state:
const App = () => {
const [state, setState] = useState({
todos:
[
{
id: 1,
title: 'take out trash',
done: false
},
{
id: 2,
title: 'wife to dinner',
done: false
},
{
id: 3,
title: 'make react app',
done: true // if I checked this checkbox.
},
]
})
您可以安全地使用 javascript 的数组 map 功能,因为它不会修改现有的 state,它的反应不喜欢,它会返回一个新数组。 该过程是循环遍历状态的数组并找到正确的 id。 更新done
的 boolean。 然后使用更新的列表设置 state。
const toggleDone = (id) => {
console.log(id);
// loop over the todos list and find the provided id.
let updatedList = state.todos.map(item =>
{
if (item.id == id){
return {...item, done: !item.done}; //gets everything that was already in item, and updates "done"
}
return item; // else return unmodified item
});
setState({todos: updatedList}); // set state to new object with updated list
}
编辑:更新代码以切换item.done
而不是将其设置为 true。
您需要像这样使用扩展运算符:
const toggleDone = (id) => {
let newState = [...state];
newState[index].done = true;
setState(newState])
}
D. Smith 的回答很棒,但可以重构为更具声明性,就像这样..
const toggleDone = (id) => {
console.log(id);
setState(state => {
// loop over the todos list and find the provided id.
return state.todos.map(item => {
//gets everything that was already in item, and updates "done"
//else returns unmodified item
return item.id === id ? {...item, done: !item.done} : item
})
}); // set state to new object with updated list
}
const toggleDone = (id) => {
console.log(id);
// copy old state
const newState = {...state, todos: [...state.todos]};
// change value
const matchingIndex = newState.todos.findIndex((item) => item.id == id);
if (matchingIndex !== -1) {
newState.todos[matchingIndex] = {
...newState.todos[matchingIndex],
done: !newState.todos[matchingIndex].done
}
}
// set new state
setState(newState);
}
所有很好的答案,但我会这样做
setState(prevState => {
...prevState,
todos: [...prevState.todos, newObj]
})
这将安全地更新 state。 也将保持数据完整性。 这也将解决更新时的数据一致性。
如果您想做任何条件,请这样做
setState(prevState => {
if(condition){
return {
...prevState,
todos: [...prevState.todos, newObj]
}
}else{
return prevState
}
})
类似于D. Smith 的回答,但更简洁一些:
const toggleDone = (id) => {
setState(prevState => {
// Loop over your list
return prevState.map((item) => {
// Check for the item with the specified id and update it
return item.id === id ? {...item, done: !item.done} : item
})
})
}
我将使用 useState 而不是另一个 state 创建 todos 数组,关键是创建 todos 数组的副本,更新它,并将其设置为新数组。 这是一个工作示例: https://codesandbox.io/s/competent-bogdan-kn22e?file=/src/App.js
const App = () => {
const [todos, setTodos] = useState([
{
id: 1,
title: "take out trash",
done: false
},
{
id: 2,
title: "wife to dinner",
done: false
},
{
id: 3,
title: "make react app",
done: false
}
]);
const toggleDone = (e, item) => {
const indexToUpdate = todos.findIndex((todo) => todo.id === item.id);
const updatedTodos = [...todos]; // creates a copy of the array
updatedTodos[indexToUpdate].done = !item.done;
setTodos(updatedTodos);
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.