Search code examples
javascriptreactjsuse-statereact-component

React Component does not re rendering when updating an object in state hooks


Why this component does not update when the state updating? But, when the file is updated (like editing and saving the code), the component will re-rendering and show the correct value from the updated state. Here is the code

import { useReducer } from "react";
import "./styles.css";

const init = [
  {
    name: "Car",
    stock: 100
  },
  {
    name: "Truck",
    stock: 50
  }
];

const reducer = (state, action) => {
  if (action.type === "add") { 
    state[0].stock++;
    return state;
  } else { 
    return state;
  }
};


export default function App() {
  const [state, dispatch] = useReducer(reducer, init);
  const addCarStock = () => {
    dispatch({ type: "add" });
  };

  return (
    <div>
      <p>Car Stock : {state[0].stock}</p>
      <button onClick={addCarStock}>Add Car Stock</button>
    </div>
  );
}

You can open this code in sandbox.io


Solution

  • When you do state[0].stock++;. It changes the existing array(you can actually check that array updated by putting a console.log(state); in the first line of reducer function) and when react does rendering it does a shallow comparison (reference checking) and ignores re-render assuming it is the same array (because prev and new state refer to the same instance).

    You need to create a new array instance (state) with the changes and return it.

    const reducer = (state, action) => {
      if (action.type === "add") {
        return state.map((item,itemIndex) => {
          if(itemIndex === 0){
            return {...item, stock: item.stock + 1}
          } else {
            return item;
          }
        });
      } else {
        return state;
      }
    };
    

    Code sandbox => https://codesandbox.io/s/recursing-davinci-iid5h?file=/src/App.js