How to update state with usestate in an array of objects?
Solution 1
You can safely use javascript's array map functionality since that will not modify existing state, which react does not like, and it returns a new array. The process is to loop over the state's array and find the correct id. Update the done
boolean. Then set state with the updated list.
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
}
Edit: updated the code to toggle item.done
instead of setting it to true.
Solution 2
You need to use the spread operator like so:
const toggleDone = (id) => {
let newState = [...state];
newState[index].done = true;
setState(newState])
}
Solution 3
D. Smith's answer is great, but could be refactored to be made more declarative like so..
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
}
Solution 4
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);
}
MFA86
Updated on December 21, 2021Comments
-
MFA86 over 2 years
I'm having some trouble with the React useState hook. I have a todolist with a checkbox button and I want to update the 'done' property to 'true' that has the same id as the id of the 'clicked' checkbox button. If I console.log my 'toggleDone' function it returns the right id. But I have no idea how I can update the right property.
The current 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> ); }
The updated state I want:
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. }, ] })