entropyfeverone
entropyfeverone

Reputation: 1572

How to avoid unnecessary re-render of a component in React?

I have this case:

const Parent = () => {
  
  const [value, setValue] = useState('');
  
  return <>
    <Child1 value={value} />
    <Child2 setValue={setValue} />
    </>
  
}

but every time setValue of Child2 is getting called, Child2 re-renders although its props have not been changed (Child1 re-renders also, but this is the expected behavior since prop value changed).

How to fix this ?

Upvotes: 3

Views: 9231

Answers (2)

Drew Reese
Drew Reese

Reputation: 202836

React useState state updater functions are guaranteed to be stable references, so Child2 is only rerendering because the parent component Parent is rerendering due to the state update. If you want to hint to React that it can likely bail on rerendering a child component then use the memo Higher Order Component.

const Child2 = ({ setValue }) => {
  ....
};

export default memo(Child2);

Demo

Demonstrates 2 "instances" of Child 2, one decorated with the memo HOC and the other not. All children use an useEffect to log when they are rendered. Note that all initially render, but only child 1 and 2 (w/o memo) continually are rerendered.

Edit how-to-avoid-unnecessary-re-render-of-a-component-in-react

Sandbox code:

import { memo, useEffect, useState } from "react";
import "./styles.css";

const Child1 = ({ value }) => {
  useEffect(() => console.log("Child 1 rendered"));
  return <div>Child1: {value}</div>;
};

const Child2 = ({ id, setValue }) => {
  useEffect(() => console.log(`${id} rendered`));
  return (
    <div>
      {id}: <input type="text" onChange={(e) => setValue(e.target.value)} />
    </div>
  );
};

const Child2wMemo = memo(Child2);

const Parent = () => {
  const [value, setValue] = useState("");

  return (
    <>
      <Child1 value={value} />
      <Child2 id="Child 2" setValue={setValue} />
      <Child2wMemo id="Child 2 with Memo" setValue={setValue} />
    </>
  );
};

export default function App() {
  return (
    <div className="App">
      <Parent />
    </div>
  );
}

enter image description here

Upvotes: 2

JBaczuk
JBaczuk

Reputation: 14619

This is the purpose of React.memo or useMemo.

Example

const Parent = () => {
  
  const [value, setValue] = useState('');
  const child2 = useMemo(() => <Child2 setValue={setValue} />, [setValue])
  
  return <>
    <Child1 value={value} />
    {child2}
    </>
  
}

[setValue] Is the dependencies array. Changes to anything in this array will cause the value to be re-calculated.

The reason it re-renders even though the props don't change is because you are changing state on the Parent component. This causes the Parent component to re-render, which will re-render all of the children regardless of whether their props change.

Alternatively, you could use React.memo on the child component like this:

const Child2 = React.memo(function Child2(props) {
  /* ... */
});

Upvotes: 2

Related Questions