Why we should not mutate state in react

Why we should not mutate state in react

In React, it is generally considered a best practice not to mutate the state variable directly. Instead, you should use the setState method provided by React to update the state. There are several reasons why mutating the state directly is discouraged:

1. Predictable Behavior: React relies on the state and props to determine when to re-render components. By using the setState method, React can accurately track changes to state and trigger re-renders when necessary. If you mutate the state directly, React may not detect the change and fail to update the component properly.

2. Immutability and Immutability Benefits: React promotes the concept of immutable data. Immutable data means that once created, the data cannot be changed. When you mutate the state directly, you are breaking this principle and introducing potential side effects and unexpected behavior.

3. Performance Optimizations: React can perform optimizations like shallow comparisons to determine if a component needs to re-render. Immutability helps with these optimizations, as React can quickly check if the reference to the state has changed. If you mutate the state directly, React might assume the state has not changed and skip re-rendering when it's necessary.

4. Undo/Redo and Time-Travel Debugging: Immutability makes it easier to implement features like undo/redo functionality and time-travel debugging, as you can keep track of previous states without worrying about mutations.

5. Functional Programming Paradigm: Immutability aligns with the principles of functional programming, making your code easier to reason about and less prone to bugs.

Example

Let's create a simple component that will reverse the array when we click the button and display it in the UI.

Wrong way of reversing the array:

import { useState } from 'react';

const initialArr = [1, 2, 3, 4, 5];

export default function List() {
// state variable and method to update it
  const [arr, setArr] = useState(initialArr);

// function to reverse the array on button click
  function handleClick() {
    arr.reverse();    // mutating the state directly
    setArr(arr);
  }

  return (
    <>
      <button onClick={handleClick}>
        Reverse
      </button>
      <ul>
        {arr.map(item => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </>
  );
}

Output:

Reason:

Array.prototype.reverse() mutates the original array in place, and then we are setting the state with the same array reference using setArr(arr). In React, when the state is set with the same reference, React doesn't detect the change, and it won't trigger a re-render.

Right Approach to Reverse:

import { useState } from 'react';

const initialArr = [1, 2, 3, 4, 5];

export default function List() {
// state variable and method to update it
  const [arr, setArr] = useState(initialArr);

// function to reverse the array on button click
  function handleClick() {
    const newArr = [...arr]; // creating new array and then reversing
    newArr.reverse()
    setArr(newArr);
  }

  return (
    <>
      <button onClick={handleClick}>
        Reverse
      </button>
      <ul>
        {arr.map(item => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </>
  );
}

Output:

Reason

This code will work as expected. By creating a new array newArr and then reversing it using newArr.reverse(), we ensure that the original arr state is not modified directly. Instead, you update the state with a new reference, which will trigger a re-render in React and reflect the reversed array in the UI.

Hope you liked the article, if yes then give a like.

Have a Look: https://www.youtube.com/@endeavourmonk