Write better JavaScript and ReactJs code with Immerjs
Tags: javascript, react, immer, datastructure
Published: 2023-05-01 12:31:33

## What is an immutable state?
It's a state that doesn't change over time.


So when we create an immutable object we don't change it's properties, If we need to change it's properties, we create a new copy of it and modify the properties as we want.


In JavaScript we can use both mutable and immutable states, We decide which is better for us, We can use **Object.freeze()** for example to make our object immutable.


Let's have an example, We've an object called state ...

```javascript
const state = {
  id: 1,
  name: 'John',
  accounts: {
    facebook: {
      id: 'facebook',
      url: '/'
    },
    twitter: {
      id: 'twitter',
      url: '/'
    }
  }
};
```

We need to modify it's twitter account url and assign it to a new state without affecting the current state, So we would do something like this

```javascript
const newState = {
  ...state,
  accounts: { ...state.accounts, twitter: { 
  ...state.accounts.twitter, url: '/newUrl' } }
};
```

This code has two main issues
1. It's so long in comparison to its purpose, I just want to update one property.
2. Readability is not so good, Why I'm seeing many properties and nested levels while I'm only updating one property?!


If we use ImmerJs, It'll be like this

```javascript
const newState = produce(state, (draftState) => {
  draftState.accounts.twitter.url = '/newUrl';
});
```
Here, we can see
1. Shorter code
2. More readable, I'm only seeing the property I'm changing!


So, Immerjs produce function creates a new draft copy of your object or array, And let you modify it as you want, Then returns you a new state with the changes you applied.



## In React
All states are immutable, When we set a state we create a new variable and assign it to the state, We don't change the current one

Let's have an example

```javascript
const [quiz, setQuiz] = useState({
   title: "Quiz 1",
   questions: [
      {
        id: "1",
        type: "mcq",
        title: "Question 1?",
        answers: [
           {
             id: "a_1",
             text: "Answer 1",
             isTrue: true
           },
           {
             id: "a_2",
             text: "Answer 2",
             isTrue: false
           }
        ]
      }
   ]
});
```

We've a state holds an object, What if we want to push a new answer to the quiz? We would do something like this

```javascript
const addAnswer = (questionId, newAnswer) => {
  setQuiz({
    ...quiz,
    questions: quiz.questions.map((question) =>
      question.id === questionId
        ? { ...question, answers: [...question.answers, 
         newAnswer] }
        : question
    )
  });
};
```

Complex, right? Here's how it's done using Immerjs

```javascript
const addAnswer = (questionId, newAnswer) => {
  setQuiz(produce(prev, (draft) => {
      const question = draft.questions.find((el) => el.id === questionId);
      question.answers.push(newAnswer);
    }
  );
};
```


So it's not just about reducing amount of code, But we only focus on what we need to change "The answer", without caring about the other quiz properties.



There's also a light package **use-immer** contains a custom hook useImmer, It's used instead of useState to call the produce function automatically when setting a state

```javascript
const [quiz, setQuiz] = useImmer({
   .....
});
```

It'll make our code more simpler

```javascript
const addAnswer = (questionId, newAnswer) => {
  setQuiz((draft) => {
    const question = draft.questions.find((el) => el.id === questionId);
    question.answers.push(newAnswer);
  });
};
```


This awesome package [immerjs](https://immerjs.github.io/immer/) makes Redux toolkit too much simpler than old redux pattern, It's automatically implemented there, So you don't need to use the many spread operators just to change one value in your reducers.

Thank you so much!