Down the rabbit hole
Give me a component A
and I'll:
On first render
- Run
A
'sstate lazy initializers
. - Render
A
. - Update the
DOM
. - Run
A
'slayout effect
s. - Paint the
DOM
updates from3
. - Run
A
'seffect
s.
On subsequent renders (props changed or state changed)
- Render
A
. - Update the
DOM
. - If any of
A
'slayout effect
s don't have a dependency array or any of its dependencies has changed, run their clean-up functions. - If any of
A
's layout effect's don't have a dependency array or any of its dependencies has changed, run them. - Paint the
DOM
updates from2
. - If any of
A
'seffect
s don't have a dependency array or any of its dependencies has changed, run their clean-up functions. - If any of
A
'seffect
s don't have a dependency array or any of its dependencies has changed, run them.
When rendering your app doesn't render A
anymore
- Run
A
'slayout effect
s' clean-up functions. - Run
A
'seffect
s' clean-up functions.
The nuance
You have probably seen (if not, you should take a deep look!) this before:
It does an awesome job at explaining the order and the phases on which stuff happens, but even though most React devs understand when their effect
s run, I've seen them having a hard time understanding not every
rerender trigger clean-ups.
When a new rerender happens, dependencies are checked. If any of the dependencies changed (or there's no dependencies array), it cleans up the previous
effect
before rerunning theeffect
.
What's a clean-up function?
The clean-up function run on the N
th render is the function returned by an effect
on render N
th - 1
.
Beware! This means clean-up functions on render N
th will likely be closed over (hold a closure
of) N
th - 1
's state!
When does a dependency change?
React uses Object.is
to compare dependencies. Object.is
is an strict equality check (===
) on esteroids: while the strict equality comparison
algorithm is meant to lie about 0 === -0
and NaN === NaN
to comply with IEEE 754
, Object.is
doesn't.
Try it yourself
Sandbox here.
Glossary
Render
(andrerender
): run a functional component's body or run a class component'srender
method. Obtaining theJSX
returned from it and handing it to React so it knows how to update theDOM
.Update the DOM
: performDOM
mutations through actual JS'sDOM
API. Updating theDOM
synchronously schedules tasks to repaint the screen that will happen asynchronously.- Paint the
DOM
updates: giving the browser a break so it can paint any scheduledDOM
update.