Home > database >  Is a component always re-rendered in the React reconciliation process?
Is a component always re-rendered in the React reconciliation process?

Time:08-12

I'm trying to understand how React "displays and update" the code below, assuming I've understood the differences and the vocabulary explained here https://reactjs.org/blog/2015/12/18/react-components-elements-and-instances.html

import React from "react";

export default function App() {

  console.log("App is rerendered")

  const [time, setTime] = React.useState(0)

  React.useEffect(() => {
    const lol = setTimeout(() => setTime(prev => prev   1), 100)
    return () => clearTimeout(lol)
  }, [time]
  )

  function ShowTime() {
    console.log("ShowTime is rerended")
    return (
      <div> Time : {time / 10} sec</div>
    )
  }

  function ShowButton() {
    console.log("ShowButton is rerended")
    return (
      <button
        onClick={() => console.log("I'm hard to click cuz rerendered the whole time :/")}>
        Button created with ShowButton component
      </button>
    )
  }

  return (
    <main>
      <ShowTime />

      <ShowButton />

    </main>
  )
}
  • React create the virtual dom with the App element, the ShowTime element, and the ShowButton element inside
  • It's the first render so React renders everything, creating an instance of App, containing a main DOM element, containing one instance of ShowTime and one instance of ShowButton
  • After 100ms, time state in App changed !
  • React update the virtual dom again taking account time state has changed
  • It's rerendering, so there is reconciliation

https://reactjs.org/docs/reconciliation.html#component-elements-of-the-same-type says "When a component updates, the instance stays the same (...). Next, the render() method is called (...)"

  • React does't care if App changed or not. It's a component, and when he encounters a component in the virtual dom, when commiting, the instance stays the same, and React runs App.render() In this case it's nice, because time state has changed.

  • Recursing process of reconciliation on children

  • In the same way, React does't care if ShowTime and ShowButton changed or not. They're components, so React keeps their instance, runs ShowTime.render() and ShowButton.render()

My two questions :

  • Is my understanding of the reconciliation process (concerning the components part) is right ?
  • So a component inside a component that has to be rendered will be rendered, whatever if it is concerned about any props or state changes or not ? (it's the case of my ShowButton component) That's weird no ? Because of that it's very hard to click it !

CodePudding user response:

  1. The declaration of ShowButton is right inside the App render function. So React not only rerender it but inserts a new DOM button element 10 times a second. That's why it is hard to click. Move ShowButton out of App.

  2. Reconciliation happens after all rendering.

  3. In some cases React doesn't rerender components. We use React.memo, PureComponent and shouldComponentUpdate for the optimization. For more information please read this answer.

  4. There are ShowTime.render() and ShowButton.render() in your text but functional components doesn't have methods.

CodePudding user response:

In the same way, React does't care if ShowTime and ShowButton changed or not. They're components, so React keeps their instance, runs ShowTime.render() and ShowButton.render()

React doesn't care, as long as it's the same component. The problem is that ShowTime and ShowButton are a new component with the same name, created every time App is rerendered. It's like saying

const ShowTime = () => {
  // ... (btw, don't do this either)
}

So while the ultimate structure is the same, React sees new components every rerender of App.

To solve this problem, pull the components out of App:

function ShowTime() { ... }

function ShowButton() { ... }

function App() { ... }
  • Related