Search code examples
reactjsreact-strictmode

How to explain the rendering result of a react component in strict mode?


The component is from React's official documentation's section Keeping Components Pure.

let guest = 0;

function Cup() {
    // Bad: changing a preexisting variable!
    guest = guest + 1;
    return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaSet() {
    return (
        <>
            <Cup />
            <Cup />
            <Cup />
        </>
    );
}

When this component is running in strct mode I expected its rendering result to be:

Tea cup for guest #4
Tea cup for guest #5
Tea cup for guest #6

However, the correct result is:

Tea cup for guest #2
Tea cup for guest #4
Tea cup for guest #6

I was confused with the correct result because according to my understanding the rendering happened twice. The steps of each rendering are App -> TeaSet -> 3 Cups. After the first rendering, the value of the guest is 3. So in the second rendering, the first cup shuld be rendered as 'Tea cup for guest #4' and so on.

Any help is appreciated!

I have debugged this component. I gave each cup an id and set a break point at the first line of the Cup component. What's strange is that the break point is met twcie at the first cup in a row!


Solution

  • I was confused with the correct result because according to my understanding the rendering happened twice. The steps of each rendering are App -> TeaSet -> 3 Cups.

    Not quite.

    App is rendered twice, and the TeaSet is rendered twice, and each Cup is rendered twice. But the rendering of App doesn't include rendering the TeaSet, and the rendering of the TeaSet doesn't include rendering the Cups.

    Instead, the rendering of App just returns a result that tells React to create a TeaSet; and the rendering of the TeaSet just returns a result that tells React to create three Cups.

    (So "rendering" in React is a bit different from how that term is usually used; actually painting the component on the screen happens long after "rendering", in the React sense, is complete.)

    The rendering of App has no side effects (I assume — you haven't posted its code), and the rendering of the TeaSet has no side effects; so it doesn't actually matter how many times they get rendered.

    The rendering of each Cup does have a side effect (incrementing guest), so you notice that it's rendered twice (due to strict mode).

    So the overall flow is something like this:

    • render App
    • render App again
    • create TeaSet component
    • render the TeaSet
    • render the TeaSet again
    • create Cup components
    • render the first Cup
    • render the first Cup again
    • render the second Cup
    • render the second Cup again
    • render the third Cup
    • render the third Cup again