Reputation: 529
I use createSlice()
from redux-starter-kit
. It's possible to mutate state in reducers thanks to immer
under the hood. But they said that there are some restrictions in immer
. For example, you shouldn't mutate AND return new state from reducers at the same time. So I select to mutate like so
first attempt
const testSlice = createSlice({
initialState: 4,
reducers:{
increment: state => {state = state + 1},
decrement: state => {state = state - 1}
}});
But this code doesn't work. Particulary, when I dispatch increment() or decrement(), I see actions in Redux Dev Tools, but state stays unchanged.
Okay. Let's return new state like so:
second attempt
const testSlice = createSlice({
initialState: 4,
reducers:{
increment: state => state + 1,
decrement: state => state - 1
}});
And this code works as expected.
After all, I've tried this construction
third attempt
const testSlice = createSlice({
initialState: {counter:4},
reducers:{
increment: state => {state.counter = state.counter + 1},
decrement: state => {state.counter = state.counter - 1}
}});
And this also works The question is - why third works and at the same time first not works?
Upvotes: 2
Views: 887
Reputation: 17844
Just expanding on Damnjan's excellent answer with examples and to also caution that passing by reference ala C++ does not exist in Javascript. Everything is pass-by-value.
When passing primitives (string, number, bigint, boolean, undefined, and symbol), a copy of the pointer is assigned to a local variable inside the function. But when the value is modified, a new value is created because primitives are by-nature immutable and the local pointer is 're-pointed' to this new memory address but not the original.
let test = { a: 0, b: 'foo', c: false };
function modifyPrimitives(a, b, c)
{
a = a + 1;
b = 'foo';
c = true;
}
modifyPrimitives(test.state);
console.log(test); // { a: 0, b: 'foo', c: false }
When passing objects, the same happens; a copy of the pointer to that object is assigned to a local variable. You can modify the nested properties of this object, BUT you cannot change the original object to point to another. You only have the local pointer and all you can do is 're-point' that to a new object.
let test = { a: 0, b: 'foo', c: false };
function modifyObject(obj)
{
obj.a = obj.a + 1;
obj.b = 'foo';
obj.c = true;
obj = { wow: 'omgwtfbbq' }; // this won't change the object outside
}
modifyObject(test);
console.log(test); // {a: 1, b: "foo", c: true}
Upvotes: 0
Reputation: 51
The reason why first example doesn't work is because you are not mutating state - you are just reassigning the variable state
that you get as the argument to your reducer. In your third attempt, you use state as an object. That object gets passed as the argument to your reducer by reference so you can modify its properties. That has nothing to do with redux, it's the way Javascript works.
Upvotes: 5