How to Use the React useEffect Hook
We've managed to use the useState Hook to track and display listings data to our UI. In this lesson, we'll introduce the useEffect Hook and see how we can create an effect callback to query listings data the moment our component mounts.
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL with a single-time purchase.

[00:00 - 00:13] In the last lesson, we observed how the used state hook was helpful in keeping track of the listing's data fetched from our query as component states. As a result, we were able to help present the listing's state data in the UI.
[00:14 - 00:31] And we were able to even refetch the query and update the state information whenever the user decided to delete or remove a listing. To be able to query all the listings from the API, we attached a click listener that called our server fetch function to make the request.
[00:32 - 00:53] Though there's nothing inherently wrong here, in a lot of the applications we use day to day, queries and the display of data is sometimes made at the moment of pages being rendered. In the context of our listings component, let's say that we want our initial query to be made when the listings component is being rendered for the very first time.
[00:54 - 01:07] To help us achieve this, we'll use another very commonly used React hook known as the use effect hook. The use effect hook allows us to perform side effects in our function components.
[01:08 - 01:22] Side effects are essentially anything where we want an imperative action to happen. API calls, updating the DOM, subscribing to event listeners, these are all side effects that we might like a component to undergo at different times.
[01:23 - 01:37] The use effect hook is sometimes a little harder to grasp than the use state hook, so we'll spend some time explaining it in a little more detail. We'll start with a brief example of the use effect hook.
[01:38 - 01:54] We'll import the use effect hook from React. And just like how we set up the use state hook at the top level of the component, we'll do the same for the use effect hook as well, but declare it right after our use state hook.
[01:55 - 02:04] The use effect hook doesn't return any values, but instead takes two arguments. The first being required and the second being optional.
[02:05 - 02:13] The first argument is the effect callback function we want the hook to run. In other words, the effect itself.
[02:14 - 02:26] To get us started, let's place a console log message within the effect callback function will specify here. When does this effect get run?
[02:27 - 02:41] By default, the effect runs when the component first renders and after every update. If we run our application right now, we'll notice the console log message is being generated as our component is being rendered.
[02:42 - 03:03] To see when a component updates, we can hit the query listings button and notice the console message be generated practically every single time the component is being updated. How would we be able to limit this effect to only run when the component is first rendered and not on update?
[03:04 - 03:19] That's where the second argument of the function comes in. The second argument is optional and it's the dependency list which allows us to tell react to skip applying the effect only until in certain conditions.
[03:20 - 03:37] If we simply place a blank empty array as the second argument, this is how we tell react to only run the effect on initial render. Now, when we launch our app, we'll notice the console message only be generated when the component first mounts.
[03:38 - 04:06] Instead of having our effect run once in the beginning and on every update, how about we attempt to restrict the effect to run only in the beginning and when the component gets updated in a specific fashion. The component simply updating is a broad term. The component can update due to when a state variable changes, when its parent gets rendered causing children components to re-render, etc.
[04:07 - 04:27] With the use effect hook dependency list, we can fine tune to which variables the hook should depend on to run the effect. For example, in our case, assume we wanted to fire a console message when the component update depends on the listing's state variable getting updated.
[04:28 - 04:43] So we'll specify the listing's value as a dependency in our use effect hook. Now, visually in our app, the console message will be run when the component mounts and every single time the listing's dependency changes.
[04:44 - 05:05] The interaction we have in our app involves the change of the listing's dependency. However, if we were to create a new state number property called count, initialize it with zero and create a click event handler that simply increments the count state property.
[05:06 - 05:23] We'll notice our effect hook doesn't run when the count state property changes. It runs on update only when the listing's value changes.
[05:24 - 05:46] If we wanted to run on both change in listings and counts, we can add the count value to the dependencies list as well. The effect callback gets run every time we specified when the effect should run .
[05:47 - 06:00] The use effect hook does also provide the capability to run a cleanup after the effect. This can be done by specifying a return function at the end of our effect callback.
[06:01 - 06:13] Assume we wanted to return a console log that simply said effect is being cleaned up. If we head to the UI, we can now observe when this cleanup is to be run.
[06:14 - 06:30] Essentially, we can see that the cleanup function is run every time before running the intended effect is about to be made. In addition, if our component was to ever unmount, the cleanup function would also run as well.
[06:31 - 06:51] This is sort of the cleanup to the initial mounting step that's also done for the effect. A good example of when we might need a cleanup is when we set up a subscription of sorts in our effect, but we want to remove the subscription whenever the next subscription call is to be made to avoid memory leaks.
[06:52 - 07:06] Okay, with that said, we've gathered enough information of the use effect hook to perform what we want to achieve. As we've mentioned earlier, we're interested in fetching the listings from our GraphQL API the moment our component is rendered.
[07:07 - 07:29] This would be fairly easy since we now know that we can have our effect only run on mount if we specify an empty array in the dependencies list. And we'll call the fetch listings function right within our effect callback, which is responsible in making our query and updating the listings state of our component.
[07:30 - 07:49] Since we'll now be able to render our list on mount, we'll remove the button we had before that was responsible in invoking the fetch listings function. Now, our listings list is shown the moment our component is rendered.
[07:50 - 08:05] We can see this whenever we decide to refresh the page. Now, by convention, some would recommend to keep the necessary request we're making, such as the server server fetch function within the use effect hook itself.
[08:06 - 08:20] But in our case, we'll just keep it as is since we need to have the fetch listings function be called in the delete listing function as well. Cool, we've done what we've intended to do.
[08:21 - 08:37] There's one other important point to make. If our effect depends on a component value that's prone to changing props or state, for example, and that value is not defined in our dependencies list, this could lead to a source of bugs.
[08:38 - 08:56] For example, assume that our hook here depends on the value of listings. And to keep it simple, let's just say that if listings was to exist and the length of the listings was graded in zero, then we should make a console message that says something whenever the component is to render.
[08:57 - 09:17] We notice an issue in our editor, since our editor now tells us to either include the missing dependency listings or remove the dependency array. This lint check comes from the React Hooks exhaustive dependencies ES lint rule that's now introduced with every create react app application.
[09:18 - 09:32] So why is this an issue? Because by not specifying a dependency that's being used in the effect, we risk our effect hook to potentially depend on stale values from previous renders.
[09:33 - 09:51] It's hard to pinpoint when something like this could happen, but if it does, it could lead to some difficult to solve bugs. This is also a reason why the React team recommends the moving of all functions that are used in the hook within the hook itself.
[09:52 - 10:00] To help a better survey, the dependencies that function might depend on. So what are we best expected to do here?
[10:01 - 10:26] We could either include the missing dependency or remove the dependencies list entirely so our hook would always run on initial render and every update. However, you may find yourself in a few sticky situations at certain times where we don't want to include a dependency, but we don't want this error to be shown.
[10:27 - 10:51] Oftentimes, you may come across some opinions online where it's suggested to just dis- disable the ES lint rule when this happens, but that's not really recommended. In the next coming lessons, we'll highlight one or two things we'll do where this issue might arise, but we're also going to provide some more detailed documentation in the lesson docs to extrapolate on this note.
[10:52 - 11:27] Okay, if we were to continue building our app this way, the pattern of having our components depend on a user fact hook to call the server function and update component state will be repeated quite a bit between a large number of components. So why don't we think about creating a custom hook that consolidates this functionality and can be used for any component that wants to query something from our GraphQL API the moment the component gets mounted.
[11:28 - 11:40] We'll set up our query fetching only when the component mounts in our hook that we can label the use query hook. We'll begin to create this hook in the next lesson.
[11:41 - 11:50] [ Silence ]