skip to Main Content

I’m trying to change state using dispatch().
So I used the (…) operator to copy the object and change the state like this: By the way, an error occurs when the event is "user-changed-channel".
No cause found. Please help.

    export default function channels(state = initialState, action) {
      // console.log(action);
      switch (action.type) {
        case SETCHANNELS: {
          if (action.event === "user-changed-channel") {
            // return { ...state, channels: {} };
          }

          const {
            event,
            socketId,
            sender,
            originChannel,
            new_channels,
            changed_channel,
          } = action;
          const obj = updateChannels({
            new_channels,
            event,
            socketId,
            sender,
            originChannel,
            changed_channel,
            state,
          });
          return { ...state, channels: obj };
        }
        default:
          return { ...state };
      }
    }
    //updateChannels function


        export function updateChannels({
         event,
         new_channels,
         originChannel,
         state,
         changed_channel,
     sender,
    }) {
     if (event === "init") {
       return new_channels;
     }
    
     if (event === "user-changed-channel") {
      const obj = { ...state.channels };
       if (originChannel !== null && originChannel !== undefined) {
        const members = { ...obj[originChannel]["members"] };
         delete members[sender.socketId];
         obj[originChannel]["members"] = members;
       }
       obj[changed_channel].members[sender.socketId] = sender;
       return obj;
      }
    }

I thought I would use the (…) operator and the object would be copied, keeping the state immutable, and then modified.However, I get the above error message only from "user-changed-channel".
I checked all the values ​​I send to dispatch() and they all come out fine too. Values ​​returned from the updateChannels function are also often passed. However, the problem only occurs when saving to state.

2

Answers


  1. You are mutating the state here:

    obj[originChannel]["members"] = members
    

    …and here:

    obj[changed_channel].members[sender.socketId] = sender;
    

    You are only creating a shallow copy, not a deep copy, so even though it’s true that obj !== state.channels we do still have obj.something === state.channels.something.

    Login or Signup to reply.
  2. const obj = { ...state.channels } only shallow copies the references into a new object reference, e.g. obj is a new object but all the properties still point into the state.channels‘s properties. Both obj[originChannel]["members"] = members; and obj[changed_channel].members[sender.socketId] = sender; are the mutations of the obj[changed_channel] object reference.

    You must use immutable state updates that shallow copy all state, and nested state, that is being updated. This means obj[changed_channel] and any additional nested properties also need to be shallow copied.

    Basic example:

    if (event === "user-changed-channel") {
      const obj = {                          // <-- new reference
        ...state.channels,                   // <-- shallow copy
        [originChannel]: {                   // <-- new reference
          ...state[originChannel],           // <-- shallow copy
          members: {                         // <-- new reference
            ...state[originChannel].members, // <-- shallow copy
            [sender.socketId]: sender
          },
        }
      };
    
      if (originChannel !== null && originChannel !== undefined) {
        delete obj[originChannel].members[sender.socketId]; // <-- safe mutation of new reference
      }
    
      return obj;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search