1

I tried using React.memo() to prevent re-rendering on one of my components but it keeps on re-rendering whenever there are changes on its Parent Component.

Here's my child component with React.memo()

const Transactions = React.memo(() => {
  console.log('rerender')

  return (
    <></>
  )
})

Here's where it's being called. Whenever I click the Add button it calls the state function setModal(true), Transactions component is being re-rendered

const ScholarHistory = ({setModal}) => {
  return (
    <div className="pml-scholar pml-scholar--column">
      <div className="pml-scholar-container">
        <button onClick={() => setModal(true)} className="pml-scholar-add-button"> Add </button>
      </div>

    <Transactions />
    </div>
  )
}

I am new to React and been exploring/creating wider projects. Any ideas why it keeps on re rendering? Thanks!

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
paoloml
  • 19
  • 1
  • 4
  • Please note that being re-rendered in react doesn't meant the DOM is changing. – evolutionxbox Dec 09 '21 at 16:27
  • When a component's parent component rerenders it necessarily rerenders all its children components so it can compute what changed and needs to be committed to the DOM. You're console logging as an unintentional side-effect so it's not an accurate measure of when the `Transactions` component is ***actually*** rerendered to the DOM. – Drew Reese Dec 09 '21 at 16:28
  • 1
    `When a component's parent component rerenders it necessarily rerenders all its children` @DrewReese That's the default behavior, but they've used React.memo in an attempt to stop that. Which is what their question is about. – Nicholas Tower Dec 09 '21 at 16:30
  • @NicholasTower React calls "render" on components during the "render phase" whenever it needs to reconcile diffs... as evolutionxbox says, this isn't the same thing as being rendered/rerendered to the DOM which is what we see happen during the "commit phase" and often consider the component being rendered. – Drew Reese Dec 09 '21 at 16:32
  • 2
    From the [react docs](https://reactjs.org/docs/react-api.html#reactmemo): _"This method only exists as a performance optimization. Do not rely on it to “prevent” a render, as this can lead to bugs."_ – evolutionxbox Dec 09 '21 at 16:32
  • @DrewReese everything you say is true. Just not sure why you're bringing it up. They're asking about why the component is rerendering (during the render phase, as you pointed out), not reconciliation or updating the dom. Ie, they want to know why their log statement is happening, when they don't expect it to. – Nicholas Tower Dec 09 '21 at 16:35
  • If OP placed the console logs in an `useEffect` hook, which is called after a component has been rerendered to the DOM, I'm certain they won't see extraneous logs. – Drew Reese Dec 09 '21 at 16:35
  • @NicholasTower Because the OP doesn't understand there are ***two*** meanings of "render" in React and conflating the unintentional side-effect exposed during React's rendering as the component rendering out to the DOM. – Drew Reese Dec 09 '21 at 16:36
  • @paolo_Ligsay: from the code you've shown, the child component should not rerender when the parent rerenders. React.memo should prevent that. Can you double check that this is an accurate recreation of your code? In particular, if the child component receives any props or uses any hooks, we'll need to know about that to diagnose why it's rerendering. – Nicholas Tower Dec 09 '21 at 16:46
  • @NicholasTower The bare console log in the body of the function component, history with questions like this asked nearly daily, empirical evidence, experience. I've found understanding how rendering works in React to be a common misconception among new developers, for the same general reason. – Drew Reese Dec 09 '21 at 16:46
  • @DrewReese K, thanks for clarifying. – Nicholas Tower Dec 09 '21 at 16:47
  • Are you sure that the props given to `Transactions` do not change between renders? – evolutionxbox Dec 09 '21 at 16:48
  • OP, please see this[lifecycle diagram](https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/) and note the the `render` function (*and remember the entire function component body **is** the render function*) is called during the "render phase".... this is where you are seeing the console logs, and note that the component isn't rendered to the DOM until the "commit phase" where effects can be called. Being rendered during the "render phase" isn't the same as being rendered during the "commit phase". – Drew Reese Dec 09 '21 at 16:51
  • Hmm, well it seems with the very trivial example `Transaction` component that even with the unintentional side-effect logging that with the `memo` HOC we don't see extraneous rerenders, see this running [codesandbox](https://codesandbox.io/s/react-memo-not-working-on-a-functional-component-z6eqm). Perhaps there's more to your code than you've led on to? – Drew Reese Dec 09 '21 at 17:02
  • I tried to remove the **setModal prop** on the ScholarHistory Component and was able to prevent the re-rendering. I am not sure what causes it as it has no relation at all to the child component other than being a prop to the parent component - ScholarHistory. – paoloml Dec 09 '21 at 17:26

2 Answers2

0

I tried to remove the setModal prop on the ScholarHistory Component and was able to prevent the re-rendering.

I am not sure what causes it as it has no relation at all to the child component other than being a prop to the parent component - ScholarHistory.

paoloml
  • 19
  • 1
  • 4
0

Coming late to the thread by putting it here for anyone still having the same issue.

I think the reason is that setModal prop somehow removes the entire parent component and therefore also removes the cached Transactions component, hence the rerender.

If you just change the parent component's prop (i.e. changing it's state) without removing it from the virtual DOM tree then the child component won't be rerendered.