Building Title Looping Functionality with the useEffect Hook

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To 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.

  • |

Lesson Transcript

  • [00:00 - 00:09] Let's finally get started with the first functionality of our hook. To start, we'll focus on being able to display and looping through an array of titles past the hook.

  • [00:10 - 00:26] First, open up the use-please-stay file and ensure that that's the one in the root SRC directory and not the one in the example folder. Now, let's allow our hook to accept parameter titles, which will be type array string.

  • [00:27 - 00:42] Next, we want the document title to animate when the tab has lost focus. Luckily, JavaScript provides a visibility change event that we can add a listener to.

  • [00:43 - 00:52] As soon as our hook mounts, we'll begin listening for this event. We can do this with React's use-effect hook, being sure to provide the empty dependency array so it fires on mount only.

  • [00:53 - 01:23] We'll call the actual event listener function handle visibility change. As I mentioned, since we only want this to run on mount, we'll pass an empty dependency list to the use-effect hook.

  • [01:24 - 01:44] Now, the first TypeScript error we have is that TypeScript cannot find the types for document since we haven't included DOM in our lib compiler options. So let's go to the TSconfig.json in our root and add the DOM library to the list of libraries.

  • [01:45 - 01:55] It's also the best practice to remove listener functions whenever a React hook un-mounce. This is possible within our use-effect hook by returning a function from use- effect.

  • [01:56 - 02:05] Whatever is in this returned function is fired as part of the un-mounting process. We can use this function to remove our event listener.

  • [02:06 - 02:21] So that's return, use an arrow function, and document. Remove event listener, visibility change, and the same function handle visibility change.

  • [02:22 - 02:41] Now we need to actually write our handle visibility change function. When the value of document.visibility state is not visible, we should be iter ating through the titles provided to our hook.

  • [02:42 - 02:49] Otherwise we should stop iterating through those titles. We can track whether or not we should be iterating through these titles using a React state variable.

  • [02:50 - 03:16] Let's create a state variable and setter pair using React's use state hook. I will call them should iterate titles and set should iterate titles.

  • [03:17 - 03:24] And initially this will be set to false. We can import that.

  • [03:25 - 03:51] And so our handle visibility change function becomes set should iterate titles based on the value of document.visibility state and when it does not equal visible. So we now have a state variable that changes when the visibility of the page changes.

  • [03:52 - 03:57] That's great. We need to add functionality to actually modify the document title.

  • [03:58 - 04:04] For this we will leverage JavaScript's set interval function. However, we can't use set interval right away.

  • [04:05 - 04:15] It's not the best idea to use set interval directly with React hooks. Like our document change function, we also need to account for cleanup and any intervals we set up to prevent memory leaks.

  • [04:16 - 04:25] This is a bit tricky to do in React, but it's definitely doable. Let's begin by writing a new custom React hook use interval.

  • [04:26 - 04:40] So we'll make a new file right alongside use please stay called use interval. So this will be export const use interval.

  • [04:41 - 04:56] And for the parameters passed to this hook, we'll at least need a callback or whatever we want to run at the given interval. And the interval itself, which will be a number.

  • [04:57 - 05:20] The first thing we'll do is store a reference to the callback that's passed in and we'll do this with the react hook use ref. We then need to make sure that every time callback changes, we're updating the current value of the callback ref.

  • [05:21 - 05:38] So once again, we require the use of use effect. And whenever this callback changes, we're going to update the current value of the callback ref.

  • [05:39 - 05:48] Finally, we can get to using JavaScript's built in set interval function. So we'll create another use effect.

  • [05:49 - 06:02] And this one will fire whenever the interval changes. So what we'll do is store the interval ID from set interval.

  • [06:03 - 06:12] And we'll call the current callback ref. And of course, at the interval provided.

  • [06:13 - 06:32] And as mentioned, the whole reason we're creating this custom hook is so we can have proper clean up of this set interval. So just as we did in use please stay, we'll use the return function in use effect here to clean up this ID.

  • [06:33 - 06:44] And that can be done by calling JavaScript's built in clear interval function with the intervals ID. We should also have a way to start and stop this set interval call from running .

  • [06:45 - 06:59] Let's add a parameter should run type Boolean to our hook. We can add should run to the dependency array in our second use effect hook.

  • [07:00 - 07:16] And when should run switches to false, we can simply return from this effect. And we now have a react lifecycle safe way of using set interval.

  • [07:17 - 07:27] Let's jump back into use please stay and start using use interval. And as we said, the trigger for iterating through our titles is this should iterate titles.

  • [07:28 - 07:45] And so for now, I will throw it into our use interval function just with an empty function. We'll do 500 milliseconds as the interval and use that should iterate title state variable as the should run trigger.

  • [07:46 - 07:58] And within this body will be the actual logic that triggers the document title change. Let's first create another state variable that will keep track of the current index of the titles array.

  • [07:59 - 08:09] I'll just call that title index. And its initial value will be zero.

  • [08:10 - 08:31] And within the interval function, we'll first create a const called next index just for improved readability, which will be title index plus one. And to safely set our title index, we will use a ternary by checking if the next index index is already at the titles.length.

  • [08:32 - 08:43] We will start back at zero. Otherwise we're safe to set the title index to that next index.

  • [08:44 - 08:51] Now finally, we've arrived at the user facing functionality of our hook. And that is setting the value of document.title.

  • [08:52 - 09:21] You can use another use effect here where the dependencies will be the titles themselves and also the title index. And since we've hooked into the title index, every 500 milliseconds when this use interval hook fires and updates the title index, we just need to set document.title to title.

  • [09:22 - 09:34] So I'm going to clean this up, save this. And now let's try out our hook to see if it's working as expected.

  • [09:35 - 09:40] First let's be sure that we're in the example project route. So I'm going to cd into the example folder.

  • [09:41 - 09:56] And before we run our custom script to copy the hook in, we also need to copy and use interval since it's used by use, please stay. So let's extend our script in the example package.json to do that.

  • [09:57 - 10:16] So I'm going to keep this command. And I'm also just going to copy the use interval hook to the folder here in our example project.

  • [10:17 - 10:32] And now we can run our copy hook script. And in the call to use, please stay in app.tsx, we'll need to add our newly required array of title strings.

  • [10:33 - 10:41] We can see of course that TypeScript is already complaining. It expects us to pass in our title's array.

  • [10:42 - 11:02] So we'll just pass in something like title one, title two, and title three. Now we can start up our example app with npm start.

  • [11:03 - 11:25] And here in the browser, if we have this react app in focus, we should of course see title one, and as we expect, the title should not be iterating because this tab is in focus. However, as soon as we open another browser tab, we see as expected, our titles are iterating as provided.

  • [11:26 - 11:39] So in summary, we created an on mount use effect hook to listen to when the visibility change event fires. And we also added in the cleanup step to remove that event listener.

  • [11:40 - 11:49] Should this hook be unmounted? And we set up a state variable to be set according to the document dot visibility state.

  • [11:50 - 12:13] We then wrote a custom use interval hook, which we would use to run our title changing functionality when should iterate titles goes to true. And finally, we hooked in to both the titles and the title index in that every time the title index changes, we set the document title according to the title's value at that title index.

  • [12:14 - 12:20] So we've already got a fully functioning react hook. In the next lesson, we'll learn how to package our hook as an npm module using rollup.