Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update single value inside array in redux

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;    
    } 
}
like image 883
faraz Avatar asked Feb 27 '18 15:02

faraz


People also ask

How do I update Redux values?

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.

How do you update an element in an 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.

How do you update an object in React Redux?

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.

Can we update state in reducer?

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.


1 Answers

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);
like image 154
Mayank Shukla Avatar answered Sep 17 '22 17:09

Mayank Shukla