If you're using Redux then you'll absolutely know about immutability, how much it's important to follow.
So we know that Reducer is the place where all good state change occurs with returning a new state and without modifying the previous state.
Imagine you're building a Bug Tracker App, and It stores all details about bug which are occurred.
Suppose your initial store looks something like this
[
{
id:"1",
description:"Bug occured in Network call",
resolved:false,
},
{
id:"2",
description:"Bug occured while Signup",
resolved:false,
}
]
Also We are logging on console every time store change using store.subscribe():
store.subscribe(() => {
console.log("store changed!", store.getState());
});
Now Suppose you are dispatching action when some developers in working on the bug to resolve it but it's not resolved yet.
Below is code of action which will take place
export const bugResolving = (id, status) => ({
type: actions.BUG_RESOLVING,
payload: {
id: id,
status: status,
},
});
And from your code you're calling store.dispatch() something like this:
store.dispatch(bugAdded("Bug occured in Network call"));
store.dispatch(bugAdded("Bug occured while Signup"));
store.dispatch(bugResolving(1, "resolving in process by devDiesel"));
And from your code you're calling store.dispatch() something like this:
store.dispatch(bugResolving(1, "resolving in process by devDiesel"));
Thus your store will look something like this:
As you can see in last store change we added status property in bug with id=1.
Now After a cup of coffee☕ the Dev was able to solve and bug was marked as solved🎯.
Hooray!!🎉🎉
As you've guessed now we want to remove the status property from store object whose id is 1, and also update the resolved to true
So in your reducer function you might write code like this:
function reducer(state = [], action) {
switch (action.type) {
case actions.BUG_ADDED:
//Some Code
case actions.BUG_REMOVED:
//Some Code
case actions.BUG_RESOLVING:
//Some Code
case actions.BUG_RESOLVED:
return state.map((bug)=> {
if (bug.id === action.payload.id){
delete bug.status;
return { ... bug, resolved:true};
}
else return bug;
default:
return store;
}
}
So we will dispatch the action like this:
store.dispatch(bugAdded("Bug occured in Network call"));
store.dispatch(bugAdded("Bug occured while Signup"));
store.dispatch(bugResolving(1, "resolving in process by devDiesel"));
store.dispatch(bugResolved(1)); //⬅This one
So when the reducer runs BUG_RESOLVED it won't work as expected and will delete the status property from previous original bug state,instead of deleting where we wanted.
And thus will only update resolved to true in last state.
Which can be seen with the help of console logging of subscribe() method as described in starting.
So Why this happened??
As JavaScript is not purely immutable language when we return new state object using return state.map((bug)=>{...})
it does shallow copy of objects.
That is the status property which we are created in previous state and status property which is we deleting are pointing to the same memory address.
Thus when we delete this property it's get deleted from both object as its referring to same location inside memory
Then How to force immutability Now??
We can do deep-copy of the object using Object.assign() method.
case actions.BUG_RESOLVED:
return state.map((bug) => {
let modifiedBug = Object.assign({}, bug);//1
if (modifiedBug.id === action.payload.id) {
modifiedBug.status = Object.assign({}, bug.status);//2
delete modifiedBug.status;//3
return { ...modifiedBug, resolved: true };//4
} else return bug;
});
In above code:
1.) We assigning new object using Object.assign() thus modifiedBug will get its own address in memory.
2.) We setting modifiedBug.status property with new bug.status using Object.assign() this will also force to have it's separate memory address
3.)Now we are deleting the modifiedBug.status which won't affect any previous bug object cause its pointing to totally different location.
4.) In last we are appending resolved:true to modifiedBug Object and returning it.
Thus now our code will work as we expected
Thank You For Reading Out.😸
Post any questions in comments if you have
Top comments (0)