The useEffect Dependency Array | Lecture 145 | React.JS 🔥
Summary
TLDRThis lecture delves into the intricacies of React's useEffect hook, explaining its dependency array and how it synchronizes effects with state and props. It highlights the importance of correctly specifying dependencies to avoid bugs and ensure that effects run only when necessary, after the component has been rendered. The talk also touches on the relationship between effects, component lifecycle, and the asynchronous nature of effect execution, emphasizing the role of useEffect as a synchronization mechanism between component state and external systems.
Takeaways
- 🔧 The `useEffect` hook can be controlled by passing a dependency array to determine when the effect should run.
- 🔄 By default, an effect runs after every render, which is often not desired behavior.
- 📋 The dependency array includes state variables and props used within the effect to guide when the effect should execute.
- 🚦 Effects are reactive, similar to how React reacts to state updates by re-rendering the UI.
- 🔗 The `useEffect` hook acts as a synchronization mechanism between the component's state/props and external systems.
- 📈 The effect will re-run whenever a dependency changes, ensuring the component stays in sync with its dependencies.
- 🚫 Omitting the dependency array or including too many dependencies can lead to performance issues or bugs, including stale closures.
- 📌 An empty dependency array means the effect will only run once, on component mount.
- 🔄 If no dependency array is provided, the effect will run on every render, which is typically undesirable.
- ⏳ Effects are executed asynchronously, after the browser has painted the component to the screen, to avoid blocking the rendering process.
- 🔄 Layout effects run before the browser paints the new screen, but their use is discouraged by the React team.
Q & A
What is the default behavior of the useEffect hook in React?
-By default, the useEffect hook runs after each and every render of the component.
How can we change the default behavior of the useEffect hook?
-We can change the default behavior by passing a dependency array as the second argument to the useEffect hook.
Why does React need a dependency array for useEffect?
-React needs a dependency array to know when to run the effect, specifically, it will execute the effect each time one of the dependencies changes.
What are the dependencies in the context of useEffect?
-Dependencies are state variables and props that are used inside the effect function.
What is the rule for including state variables and props in the dependency array?
-Each and every state variable and prop used inside the effect must be included in the dependency array.
What is a stale closure and how does it relate to useEffect?
-A stale closure is a bug that occurs when React doesn't know about a change in the title or user rating, and therefore doesn't re-execute the effect code, leading to outdated state.
How does the useEffect hook act as a synchronization mechanism?
-The useEffect hook acts like an event listener for dependencies, executing the effect again when one of the dependencies changes, thus keeping the component synchronized with the state of the application.
What happens if an effect does not have any dependencies?
-If an effect has no dependencies, it will only run once, on mount, because it doesn't use any values relevant for rendering the component.
Why are effects executed after the browser has painted the component instance on the screen?
-Effects are executed after the paint phase to avoid blocking the rendering process, especially when effects contain long-running processes like fetching data.
What is a layout effect and when is it used?
-A layout effect is a type of effect in React that runs before the browser paints the new screen. It is rarely needed and discouraged by the React team.
What is the timeline of events when a component renders and re-renders?
-The timeline starts with mounting the component, followed by rendering, committing the result to the DOM, painting the changes onto the screen, and finally executing effects after the screen has been updated.
Outlines
🔄 Understanding the useEffect Hook and Dependency Array
This paragraph explains the purpose and functionality of the useEffect hook in React, emphasizing the importance of the dependency array. It clarifies that the useEffect hook is used to control when effects should run, which is determined by the state of the dependencies specified in the array. The speaker also introduces the concept of stale closure and hints at further discussion on this topic. The paragraph highlights that effects are reactive, similar to how React responds to state updates, and that they are used to synchronize a component with an external system, such as updating the document title based on component state or props.
🔄 Synchronization and the Component Life Cycle
The second paragraph delves into how effects are synchronized with the state of the application and how they are deeply connected to the component's life cycle. It explains that effects are not just for side effects but are also a synchronization mechanism. The speaker clarifies that effects will re-run whenever a dependency changes, leading to a re-render of the component. The paragraph also discusses the different types of dependency arrays and their impact on synchronization and the life cycle, including the initial render, re-renders, and the execution of effects after the render process.
🕒 Execution Timing of Effects
The final paragraph addresses the timing of effect execution during the render and commit process. It clarifies that effects are executed asynchronously, after the browser has painted the component instance to the screen. This is to prevent long-running processes, like data fetching, from blocking the rendering process and causing a poor user experience. The paragraph also touches on the need for an additional render if an effect sets state, and briefly mentions layout effects, which run before the browser paints the new screen, though their use is discouraged.
Mindmap
Keywords
💡useEffect
💡dependency array
💡stale closure
💡synchronization
💡component life cycle
💡asynchronous execution
💡layout effect
💡re-render
💡empty dependency array
💡no dependency array
Highlights
The useEffect hook can change the default behavior of running after every render by using a dependency array.
React doesn't know when to run the effect without a dependency array.
The effect will execute each time a dependency changes.
Dependencies are state variables and props used inside the effect.
Each state variable and prop must be included in the dependency array.
Not including dependencies in the array can lead to a bug called stale closure.
The useEffect hook acts like an event listener for dependencies.
Effects are reactive, similar to how React reacts to state updates.
Effects are used to keep a component synchronized with an external system.
The dependency array is crucial for the useEffect hook's functionality.
Effects and the component life cycle are deeply interconnected.
The useEffect hook is about synchronization and the component life cycle.
An empty dependency array means the effect runs only on mount.
No array at all means the effect runs on every render, which is usually undesirable.
Effects are executed after the browser has painted the component instance on the screen.
Effects may contain long-running processes like fetching data.
If an effect sets state, a second additional render is required.
Layout effects run before the browser paints the new screen and are discouraged by the React team.
Transcripts
So, I have mentioned
the use effect dependency array a few times already,
but we don't know yet what it actually does
and how it works.
So, let's change that in this lecture.
So, as we saw at the beginning of this section,
by default in effect will run after each and every render.
However, that's almost never what we want.
But, the good news is
that we can change this default behavior
by passing a dependency array into the useEffect hook
as a second argument,
but why does use effect actually need
an array of dependencies, you might ask?
Well, the reason is that without this array,
React doesn't know when to actually run the effect.
But, if we do specify the effect dependencies
by passing in the dependency array,
the effect will be executed each time
that one of the dependencies changes.
And, we will come back to why this is so amazing
in the next slide.
But, for now, this is all you need to know.
Now, what exactly are those dependencies?
Well, effect dependencies are state variables
and props that are used inside the effect.
And, the rule is that each
and every one of those state variables and props
must be included in the dependency array.
But, let's take a look at an example
to understand what I'm talking about.
And, the code here is really not important.
What matters is that the effect uses the title prop
and the user rating state.
We can clearly see at the top of the code
that title is indeed a prop
and that user rating is indeed a APs of state.
Therefore, both of them must be included
in the dependency array.
So, the effect function depends on these variables
to do its work,
and therefore we need to tell React about them.
Otherwise, if the title or the user rating changes,
React will not know about this change,
and, therefore, it won't be able to re-execute
the effect code.
And, this will then lead to a bug called stale closure.
And, we will talk about what a stale closure is
and also about some more rules for the dependency array
in a later more advanced section.
But, for now, let's actually understand
why the dependency array is so important
for the useEffect hook.
So, I like to think of the useEffect hook
as an event listener that is listening
for one or more dependencies to change.
And, when one of the dependencies does change,
use effect will simply execute the effect again.
So, a bit like a regular event listener,
but for effects.
But, let's go back to our previous example
where we had the title and user rating dependencies
in the array.
So, whenever the title or the user rating changes,
React will execute the effect again.
So, it will run the code one more time,
which will in turn update the document title.
So, the website title that we see in a browser tab.
So, essentially, effects react to updates
to state and props that are used inside the effect,
because, again, those are the effects' dependencies.
So, in a way, effects are reactive,
just like React reacts to state updates
by re-rendering the UI.
And, this is extremely useful and powerful,
as we will see throughout the rest of the course.
But, all this only works if we correctly specify
the dependency array.
Okay, but now let's remember how I said
in the very first lecture about effects,
that effects are used to keep a component synchronized
with some external system.
So, some system that lives outside of our React based code.
And, if we think about it,
that's exactly what is happening here.
So, the state and props of our component
are now in fact synchronized with an external system,
which is, in this case, the title of the document.
Now, updating the title in some other way
will, of course, not magically update the title
or user rating.
So, the synchronization only works in one way,
but that's not really the point.
The same actually happens with state updates
and we still say that the UI is in sync with state.
So, the point is that use effect
truly is a synchronization mechanism,
so a mechanism to synchronize effects
with the state of the application.
And, you will discover this
each time that you're going to use an effect.
And, so let's go explore this a little bit further.
So, as we just learned, whenever a dependency changes,
the effect is executed again.
But, now, let's remember that dependencies
are always state or props.
And, what happens to a component each time that its state
or props are updated?
Well, that's right.
The component will re-render.
This means that effects
and the life cycle of a component instance
are deeply interconnected.
That's why when the useEffect hook was first introduced,
many people thought that it was a life cycle hook
rather than a hook for synchronizing the component
with a side effect.
Now, the conclusion and the big takeaway from this
is that we can use the dependency array
in order to run effects
whenever the component renders or re-renders.
So, in a way, the useEffect hook
is actually about synchronization
and about the component life cycle.
Okay, and so with this knowledge,
let's look at the three different types of dependency arrays
that we can specify
and also how they affect both synchronization
and life cycle.
So, when we have multiple dependencies
like in this first example, variables X, Y, and Z,
it means that the effect synchronizes with X, Y, and Z.
Now, in terms of the life cycle,
it means that the effect will run on the initial render
and also on each re-render triggered by updating
one of the dependencies X, Y, or Z.
So, again, just to make this crystal clear,
the effect will be executed each time
the component instance is being re-rendered
by an update to X, Y, or Z.
But, if some other piece of state or prop is updated,
then this particular effect will not be executed.
Now, if we have an empty dependency array,
that means that the effect synchronizes
with no state or props,
and therefore it will only run on mount.
In other words, if an effect has no dependencies,
it doesn't use any values that are relevant
for rendering the component.
And, so, therefore, it's safe to be executed only once.
Finally, if we have no array at all,
we already know that the effect will run on every render,
which is usually a really bad idea and not what we want.
Now, if the effect runs on every render,
that basically means that the effect
synchronizes with everything.
So, essentially every state and every prop in the component
will be dependencies in this case.
And, now, to finish,
let's look at when exactly effects are executed
during the render and commit process.
Now, I mentioned in the first lecture on effects
that effects are executed after render.
And, while that's not wrong, it's also not the full story.
So, let's look at a timeline of events that happen
as components render and re-render.
And, I found this extremely useful
when I first learned about the useEffect hook myself.
And, so I think that you will benefit from this as well.
So, as we already know,
the whole process starts with mounting
the component instance,
in this case an instance of movie details.
After that, the result of rendering
is committed to the dom,
and finally the dom changes are painted onto the screen
by the browser.
So, this is just what we learned in the previous section,
but where do effects come into play here?
Well, effects are actually only executed
after the browser has painted the component instance
on the screen.
So, not immediately after render,
as you might have thought initially.
That's why we say that effects run asynchronously
after the render has already been painted to the screen.
And, the reasons why effect work this way
is that effects may contain long-running processes,
such as fetching data.
So, in a situation like that,
if React would execute the effect
before the browser paints a new screen,
it would block this entire process,
and users would see an old version of the component
for way too long.
And, of course, that would be very undesirable.
Now, one important consequence of the fact
that effects do not run during render
is that if an effect sets state,
then a second additional render
will be required to display the UI correctly.
And, so this is one of the reasons
why you shouldn't overuse effects.
Okay, but moving on now,
let's say that the title was initially set to Interstellar,
but then it changes to Interstellar Wars.
And, since this title is a prop,
it means that the component will re-render,
and the dom changes will be committed
and painted to the screen again.
Now, since title is part
of the dependency array of this effect,
the effect will be executed again at this point.
So, just as we learned in the last slide.
And, this whole process can of course be repeated
over and over again
until this movie details instance
finally unmounts and disappears from the screen.
Now, you might notice that there is actually a hole
between the commit and browser paint, right?
And, the reason is that, in React,
there's actually another type of effect
called a layout effect.
So, the only difference between a regular effect
and a layout effect is that the layout effect runs
before the browser actually paints the new screen.
But, we almost never need this.
And, so the React team actually discourages
the use of this use layout effect hook.
I simply mentioned this here
so that you know that this also exists.
And, actually, there are even two more holds
in this timeline.
But, we will talk about these mystery steps
by the end of the section.
So, stay tuned for that.
関連動画をさらに表示
A First Look at Effects | Lecture 141 | React.JS 🔥
useEffect to the Rescue | Lecture 140 | React.JS 🔥
The useEffect Cleanup Function | Lecture 151 | React.JS 🔥
Goodbye, useEffect - David Khourshid
Rules for Render Logic: Pure Components | Lecture 131 | React.JS 🔥
ReactJS Course [6] - Component Lifecycle | UseEffect Tutorial
5.0 / 5 (0 votes)