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
You are mutating the state here:
…and here:
You are only creating a shallow copy, not a deep copy, so even though it’s true that
obj !== state.channels
we do still haveobj.something === state.channels.something
.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 thestate.channels
‘s properties. Bothobj[originChannel]["members"] = members;
andobj[changed_channel].members[sender.socketId] = sender;
are the mutations of theobj[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: