skip to Main Content

I am trying to update the user object’s blockedUsers array, while keeping other data not changed. user object can have blockedUsers array or not, it is not certain. In slice I have:

    reducers: { CHANGE_USER: (state, action) => {
      state.user.push(action.payload)
    },
   }

And in component, I am trying to update this way:

dispatch(CHANGE_USER({blockedUsers: [...user?.blockedUsers, selectedUser] }))

where selectedUser is an object: {id: "xxxx", name: "yyyy"}. But error comes:

Possible unhandled promise rejection (id:2). 
TypeError: Invalid attempt to spread non-iterable instance. In order to be iterable, non-array objects must have a [Symbol.iterator()] method.

Also, when I try this way:

dispatch(CHANGE_USER(blockedUsers?.selectedUser))

then, another Error:

ReferenceError: Property 'blockedUsers' doesn't exist

How can I solve this?

3

Answers


  1. Try this i think this is happening cause you’re directly spreading object in a array.

    dispatch(CHANGE_USER({blockedUsers: [{…user?.blockedUsers, selectedUser}] }))

    Login or Signup to reply.
  2. The error you are getting is because user?.blockedUsers might be undefined, and spreading an undefined value produces the error you are seeing.

    Solution
    You safely update the blockedUsers array by checking first whether it exists. If it is undefined, you initialize it as an empty array, and then you can spread it.

    Here’s how you can handle that:

    1. Check if blockedUsers exists: Use the || [] fallback, to make sure you’re always spreading an array and never undefined

    2. Update reducer logic: Instead of using state.user.push(), update state accordingly, merging the existing state with the new values.

    Updated Reducer:
    Keep in mind that your reducer updates the user object accordingly, merging the old values with the new one.

    Do that this way:

    reducers: {
      CHANGE_USER: (state, action) => {
        // Merge the existing user object with the updated fields
        state.user = {
          ...state.user, // Keep existing properties of the user
          ...action.payload // Merge in the new fields (like blockedUsers)
        };
      },
    }

    Dispatching the Update:
    Now, when dispatching, ensure that blockedUsers exists or falls back to an empty array:

    dispatch(CHANGE_USER({
      blockedUsers: [...(user?.blockedUsers || []), selectedUser]
    }));

    Explanation:

    1. user?.blockedUsers || []: This checks whether blockedUsers exists; if not, it defaults to an empty array ([]).

    2. state.user = { .state.user, .action.payload }: In this way, you make sure you are updating only the properties passed in the payload-for example, blockedUsers-without overwriting the whole user object.

    This would avoid the "Invalid attempt to spread non-iterable instance" error and update your blockedUsers array correctly.

    Login or Signup to reply.
  3. If users is an object with a property blockedUsers, to update it you should be doing the following within the reducer

    CHANGE_USER: (state, action) => {
     if(!action.payload) return;
     state.user = { 
      ...state.user, 
      blockedUsers = [
       ...(state.user.blockedUsers || []),
       ...action.payload ]
     };
    }
    

    This takes the existing user states and assures that it remains the same, and for the blockedUsers it will keep all the users that are already within the array and add whatever is in the payload.
    The payload should now be something like this for this to work as expected

    dispatch(CHANGE_USER(usersToBlock))
    

    usersToBlock has to be an array, let me know if this causes any new errors.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search