Why does React re-renders children when props does not change?

Viewed 67

Consider the following example:

import "./styles.css";
import React from "react";

function Children(props) {
  const counter = props.counter2;
  console.log("re-rendering children");
  return (
    <div className="App">
      <p>counter2 value = {counter} </p>
    </div>
  );
}

export default function App() {
  const [counter, setCounter] = React.useState(0);
  const [counter2] = React.useState(0);
  return (
    <div className="App">
      <p>counter value = {counter} </p>
      <button onClick={(e) => setCounter((c) => c + 1)}>increment</button>
      <Children counter2={counter2} />
    </div>
  );
}

The Children component does not depend on the parent state counter, but when I click the button I can see that re-rendering log printed every time I click. If I am not mistaken then it means the Children component is re-rendered. My question is why? It should not re-render as the props did not change.

code sandbox: https://codesandbox.io/s/modern-dawn-xj9b8

2 Answers

Because of the lifecycle of React, when you are using a functional component, it is also considered stateless and will re-render every time there is an update in its parent component, whether there is a change in props passing into the child.

There are two ways you can do to change this behaviour,

  1. use class component and decide whether to update it using shouldComponentUpdate

  2. or the recommended way using React.memo,

import "./styles.css";
import React from "react";

function Children(props) {
  const counter = props.counter2;
  console.log("re-rendering children");
  return (
    <div className="App">
      <p>counter2 value = {counter} </p>
    </div>
  );
}

const MemoChild = React.memo(Children);

export default function App() {
  const [counter, setCounter] = React.useState(0);
  const [counter2] = React.useState(0);
  return (
    <div className="App">
      <p>counter value = {counter} </p>
      <button onClick={(e) => setCounter((c) => c + 1)}>increment</button>
      <MemoChild counter2={counter2} />
      {/* <Children counter2={counter2} /> */}
    </div>
  );
}

More on React.memo in the docs

If your component renders the same result given the same props, you can wrap it in a call to React.memo for a performance boost in some cases by memoizing the result. This means that React will skip rendering the component, and reuse the last rendered result.

this answer is true that you can use React.memo but before start using, check some articles to figure out when it's valuable to use it. using it inappropriate could damage your performance.

Related