5

I'm trying to figure out width update value of item in nested array of reducer and change value.

Its my reducer state:

let initialState = {
   data: {
     users: [
        {
            id: 1,
            name: 'a'
        },
        {
            id: 2,
            name: 'b'
        }
     ]
   }
}

and I want to change name of item in data.users but I can't access there

How can I do this?

I tried this

case SET_NAME:
        return {
          ...state,
          users: state.data.users((item, i) =>
            item.id == action.payload.id ? { ...item, value: action.payload.value} : null
          )
        };

but I can't access the users

2
  • what do you get when you log state.data.users before return statement Commented Aug 21, 2019 at 22:00
  • A blank object in root state not in data Commented Aug 21, 2019 at 22:08

3 Answers 3

4

Have a spread party...

case SET_NAME:
  return {
    ...state,
    data: {
      ...state.data,
      users: [
        ...(state.data.users.map(user =>
          user.id === action.payload.id
          ? { ...user, value: action.payload.value }
          : user
        ))
      ]
    }
  };
Sign up to request clarification or add additional context in comments.

Comments

2

It seems like there are 3 issues with your reducer:

  • data is missing in your returned object
  • the call to the map function of the users array is missing
  • your example would set any item which is not matching the id of the action to null instead of preserving it.

You probably ment to do this:

return {
    ...state,
    data: {
        ...state.data,
        users: state.data.users.map(item =>
            item.id == action.payload.id ? { ...item, value: action.payload.value } : item
        )
    }
};

for this action:

{
   type: SET_NAME,
   payload: { id: 1, value: 'test' }
}

the resulting state will be this:

{
   data: {
     users: [
        {
            id: 1,
            name: 'a',
            value: 'test'
        },
        {
            id: 2,
            name: 'b'
        }
     ]
   }
}

If you want to set the name to the value from the action, you can just override it in the reducer. In that case the whole reducer would be:

return {
    ...state,
    data: {
        ...state.data,
        users: state.data.users.map(item =>
            item.id == action.payload.id ? { ...item, name: action.payload.value } : item
        )
    }
};

and the result state for the above action would be this:

{
   data: {
     users: [
        {
            id: 1,
            name: 'test'
        },
        {
            id: 2,
            name: 'b'
        }
     ]
   }
}

Comments

1

Try this:

return {
    ...state,
    data: {
            // add "state.data" if there is any other data than the users 
            // array that you don't want to be removed or changed  
            ...state.data,
            users: state.data.users((item, i) =>
                item.id == action.payload.id
                ? { ...item, value: action.payload.value }
                : null
            )
        }

If it didn't, this should work:

// Will loop over the existing users array in the state and return an array.
const updatedUsers = state.data.users.map((item, i) => {
            // If the item exist and matches the id of the payload,
            // it will update it
            if (item.id === action.payload.id) {
                item.value = action.payload.value;
            }
            return item;
        });

        // And here is a console log to see the updated array
        console.log(updatedUsers)

        return {
            ...state,
            // This is how you update a nested array
            data: { ...state.data, users: updatedUsers }
        };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.