When does React.memo() compare component props?

Viewed 23

From what I know, React.memo() compares props to see if the component should be re-rendered or not. But React doesn't re-render components if the previous props and current props are the same even when the component is not wrapped by React.memo(). So, react.memo() compares props before component re-evaluation, not before re-render?

2 Answers

It compares them just before rendering, same as without React.memo().

But you're not quite right in thinking that React doesn't re-render your component if your props haven't changed. If one of your parent components' props/state have changed, it will re-render all of that component's children (and grandchildren), even if their props haven't changed.

So using React.memo() on one of those children prevents the re-rendering of that branch of the tree, if its props haven't actually changed.

But React doesn't re-render components if the previous props and current props are the same even when the component is not wrapped by React.memo().

Sure it does, both in functional components:

const Child = () => {
  console.log('child rendering');
  return 'foo';
};
const App = () => {
    const [parentState, setParentState] = React.useState(0);
    React.useEffect(() => {
      setParentState(1);
    }, []);
    return (
      <div>
        <div>{parentState}</div>
        <Child />
      </div>
    );
};

ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div class='react'></div>

and in class components:

class Child extends React.Component {
  render() {
    console.log('child rendering');
    return 'foo';
  }
}
class App extends React.Component {
  parentState = 0;
  componentDidMount() {
    this.setState({ parentState: 1 });
  }
  render() {
    return (
      <div>
        <div>{this.parentState}</div>
        <Child />
      </div>
    );
  }
};

ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div class='react'></div>

Unless you've set things up to memoize the component in some way, the component will re-render even if neither props nor state has changed.

The comparison that React.memo does to determine whether a component should be re-rendered whenever the component is called. That is, if you have

const SomeComponent = React.memo(function MyComponent(props) {
  // ...

Then React.memo will perform comparisons whenever the engine, while rendering, comes across a call to SomeComponent, eg:

const App = () => {
  return (
    <div>
      <SomeComponent />
    </div>
  );
};

Above, whenever App re-renders, SomeComponent will be called again. React.memo then decides whether the underlying component needs to be re-run, or whether the values returned by the previous render can be re-used. If it does need to be re-run, then it'll run the original MyComponent.

Related