DEV Community

Cover image for Remove a property of an object immutably in REDUX JavaScript
Karan-Munjani
Karan-Munjani

Posted on

Remove a property of an object immutably in REDUX JavaScript

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,
 }
]
Enter fullscreen mode Exit fullscreen mode

Also We are logging on console every time store change using store.subscribe():

store.subscribe(() => {
  console.log("store changed!", store.getState());
});
Enter fullscreen mode Exit fullscreen mode

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,
  },
});
Enter fullscreen mode Exit fullscreen mode

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"));
Enter fullscreen mode Exit fullscreen mode

And from your code you're calling store.dispatch() something like this:

store.dispatch(bugResolving(1, "resolving in process by devDiesel"));
Enter fullscreen mode Exit fullscreen mode

Thus your store will look something like this:
image

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;
    }
}

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

See In this picture:
image

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;
      });

Enter fullscreen mode Exit fullscreen mode

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

image

Thank You For Reading Out.😸

Post any questions in comments if you have

Top comments (0)