I am currently learning react and have stumbled upon a section in their ‘tutorial’ section called ‘Describing the UI’. I can’t grasp my mind around understanding a subsection called ‘Keeping components pure’.
The thing I don’t understand is this:
Given this code:
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 />
</>
);
}
Why does the output look like this:
Tea cup for guest #2
Tea cup for guest #4
Tea cup for guest #6
And not like this:
Tea cup for guest #1
Tea cup for guest #2
Tea cup for guest #3
I tried to figure it out myself but I can’t.
2
Answers
In development mode React renders your component twice, this is usefull for debugging (makes it easier to find unwanted behaviors, most obvious use case would arguably be
useEffect()
).I suspect you have a
<React.StrictMode/>
element in your index.js, that’s the component responsible for this behavior, but i would advise against removing it.If a render is a step then all calculation must be step-relevant, i would definitely advise against having an outside variable used in one of your components, the "right" way to do that would be to have another component responsible for rendering
<Cup/>
and passing the value as a prop.This likely happens becuase, in development mode, React renders everything twice on mount. You can witness this by adding the following into
Cup
:Even though the
useEffect
has no dependencies and should only run once, you would see "cup" printed twice perCup
.With that in mind, each
Cup
component is being rendered twice. You have three, and therefore the final render displays the result after the second render for each, settling on 2, 4, and 6.However, keeping state in a global variable like this is not the move, and leads to unexpected behaviour. Given that, as you mention,
Cup
should be a "pure" component, its dependency on the global variableguest
is counter-intuitive.A better approach would be to tell
Cup
to take some input, and always display that input. This is calledprops
(short forproperties
), and allows you to render your cups purely based on a state, which is managed elsewhere. A serving suggestion:This opens up the possibility of keeping a state of guests in
TesSet
then looping over it. A more advanced example:This allows you to manipulate the state from within
TeaSet
without it affecting individual cups for existing guests, and without relying on any global variable, which may be handled in unexpected ways.