Skip to content
Advertisement

React Reconciliation Of Component Instances

I’ve been trying to understand react reconciliation and am getting really confused by some of the details of how the diffing algorithm works. So far, I understand that whenever an update is made, we create a new react element tree and compare it with our previous react element tree. The diffing algorithm manages finding the difference between the new and old react element trees. The 2 assumptions of the algo. are that elements of the same level and type don’t need to be unmounted and re-mounted and that keys provide a way of identifying child elements not by index.

The part that confuses me is how comparisons are made between 2 react instances. For example, when comparing <Comp1/> in the old react element tree and <Comp2/> in the new react element tree (assume that <Comp2> replaced <Comp1> in the creation of the new tree), does the diffing algorithm simply compare both react elements’ “type” attributes? So if both have the same “type”, then the diffing algorithm doesn’t consider un-mounting and mounting into the DOM?

Answer

does the diffing algorithm simply compare both react elements’ “type” attributes?

Yes, from the docs:

Whenever the root elements have different types, React will tear down the old tree and build the new tree from scratch. Going from <a> to <img>, or from <Article> to <Comment>, or from <Button> to <div> – any of those will lead to a full rebuild.

Another your question:

So if both have the same “type”, then the diffing algorithm doesn’t consider un-mounting and mounting into the DOM?

Yes, in that case React just updates the existing instance. During component update instance remains the same, and state is maintained across renders.


You can see in below example:

  • The first place where we rendered A, it doesn’t get unmounted when we replace it also with another A (because of same type).
  • The second place where we used A, as soon as we replace it with B, react unmounts A.

let A = (props) => {
  React.useEffect(() => {
    console.log('Mounted A', props);
    return () => {
      console.log('Unmounted A', props);
    };
  }, []);
  return <div>This is A: {props.tmp}</div>;
};

let B = (props) => {
  React.useEffect(() => {
    console.log('Mounted B', props);
    return () => {
      console.log('Unmounted B', props);
    };
  }, []);
  return <div>This is B</div>;
};

  function App() {
  let [tmp, setTemp] = React.useState(0);
  return (
    <div
      onClick={() => {
        setTemp(tmp + 1);
      }}
    >
      {tmp % 2 == 0 ? <A id="first A"/> : <A id="second A"/>}
      {tmp % 2 == 0 ? <A id="third A"/> : <B />}
      <p>Start editing to see some magic happen :)</p>
    </div>
  );
}

ReactDOM.render(<App />,document.getElementById("react"));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Advertisement