skip to Main Content

I am reading the latest official react docs, https://react.dev/learn/preserving-and-resetting-state. There is one concept which i could not understand and hope someone could help.

The doc mentions React keeps state for as long as the same component is rendered at the same position.

Below one is a same place example and Counter component will share same state.

{isPlayerA ? (
        <Counter person="Taylor" />
      ) : (
        <Counter person="Sarah" />
      )}

Below is an example of different places.. Does anyone knows why it behave like that? thank you.
enter image description here

2

Answers


  1. This is sort of a guess so take with a pinch of salt but…

    When JSX gets compiled each of the { ... } parts (along with any elements) gets turned into an entry in a childrens array that gets passed to something equivalent to React.createElement(). Each of these entries can resolve to null / false, so won’t appear in output but would still take up a slot in the childrens array.

    For example:

    const Comp = () => {
      const dave = null;
      return (
        <div>
          {'Wibble'}
          {dave && <bob />}
          {!dave && <fred />}
        </div>
      );
    };
    

    might become the equivalent of something like:

    React.createElement(
      'div',
      {},
      'Wibble',
      dave && React.createElement("bob", {}),
      !dave && React.createElement("fred", {})
    )
    

    where 'Wibble', dave && React.createElement("bob", {}), !dave && React.createElement("fred", {}) will become the items in the children array used by React to track the child elements. In this case dave && React.createElement("bob", {}) and !dave && React.createElement("fred", {}) will have separate indexes in the array and therefore separate positions in the output even though dave && React.createElement("bob", {}) resolves to null and therefore doesn’t output anything.

    In the first example you gave

    {isPlayerA ? (
      <Counter person="Taylor" />
    ) : (
      <Counter person="Sarah" />
    )}
    

    would resolve to one entry in the children array and so each branch of the ternary operator would have the same position in the childrens array.

    Example JSX to JS output with Babel.

    Login or Signup to reply.
  2. Also guessing a bit here, but this behavior seems like a result of the react internal algorithm that creates the react-"UI tree" from JSX markup.

    Remember that it’s the position in the UI tree—not in the JSX markup—that matters to React!

    See react docs

    Now, at least to me, it’s not always clear how react proceeds to generate the UI tree from JSX in detail, but:

    A JavaScript && expression returns the value of its right side (…) if the left side (…) is true. But if the condition is false, the whole expression becomes false. React considers false as a “hole” in the JSX tree, just like null or undefined, and doesn’t render anything in its place.

    See react docs

    This sounds like this "hole" is present in the UI-tree, meaning that && creates an own position for the component if the condition is true and also removes it from there if the condition is false.

    On the other hand, when react reads the ternary operator (? :) it seems to try to switch out the components at the same tree position. This would make sense with this "hole" argumentation, since in this case, there is no false or undefined that react could consider as a "hole".

    Correct me if I’m wrong, but this is my understanding so far.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search