I am creating a todolist with react
and redux
and when I update redux state array it doesn't re-render, My state is actually an array which contains objects, something like this:
[{index:1,value:'item1',done:false}, {index:2,value:'item2',done:false}]
What i want to do is on click i want to toggle the value of done to 'true', But somehow I am unable to do that.
This is what I was doing in my reducer:
list.map((item)=>{
if(item.index===index){
item.done=!item.done;
return [...state,list]
}
But it doesn't re-render even though done keeps changing on clicking the toggle button.
It seems that somehow I am mutating the state. please tell me where am I going wrong and what should I do instead.
Could you give examples of something similar. I can update state of simple arrays correctly, but doing it for an array containing objects , is what's confusing me. so, could you give examples of that?
Here's the full reducer code:
export default function todoApp(state=[],action){
switch(action.type){
case 'ADD_TODO':
return [...state,action.item];
case 'TOGGLE_TODOS':
const index = action.index;
const list = state;
list.map((item)=>{
if(item.index===index){
item.done=!item.done;
}
return [...state,list];
});
default:
return state;
}
}
First, we will find the index of the item in the array using findIndex() . Then we make a copy of the todos array from the state. Then we can change the value in the new array using the index value we got from findIndex() . Lastly, in the return, we reassign todos to that new array.
To update all the elements of an array, call the forEach() method on the array, passing it a function. The function gets called for each element in the array and allows us to update the array's values. Copied! const arr = ['zero', 'one', 'two']; arr.
Redux: Update an Object When you want to update the top-level properties in the Redux state object, copy the existing state with ... state and then list out the properties you want to change, with their new values.
The state is updated and managed by reducers. Reducers always have to return something even if it's null ; they should never return undefined . If a reducer's state is an object, you must always return a new object instead of editing the object in place.
It seems that somehow I am mutating the state.
Correct you are mutating the state, because in js, variable always get reference of object/array. In your case item
will have the reference of each object of the array and you are directly mutating the value of item.done
.
Another issue is you are not returning the final object properly, also you need to return value for each map iteration otherwise by default it will return undefined
.
Write it like this:
case "TOGGLE_TODOS":
return list.map((item) => (
item.index===index? {...item, done: !item.done}: item
))
Or:
case 'TOGGLE_TODOS':
const index = action.index;
const newState = [ ...state ];
newState[index] = { ...state[index], done: !newState[index].done };
return newState;
Full Code:
export default function todoApp(state=[], action){
switch(action.type){
case 'ADD_TODO':
return [...state, action.item];
case 'TOGGLE_TODOS':
const index = action.index;
return state.map((item) => (
item.index===index? {...item, done: !item.done}: item
))
default:
return state;
}
}
Check this snippet:
let list = [
{done:true, index:0},
{done:false, index:1},
{done: true, index:2}
]
let index = 1;
let newList = list.map(item => (
item.index===index? {...item, done: !item.done}: item
))
console.log('newList = ', newList);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With