Debounce Callbacks on DOM events in React Apps

Tyler Clark
InstructorTyler Clark
Share this video with your friends

Social Share Links

Send Tweet
Published 3 years ago
Updated 2 years ago

Debouncing means managing the number of calls made within a given amount of time. The most popular time to debounce within a React application is when working with the scroll event. Let’s add a debounce function around a function listening to the scroll event.

Instructor: [0:01] On the Dashboard, as you can see here, we're currently, outside of some warnings, we don't have anything rendering to the console. We can browse the page and click on things, but we have no console.logging that's happening right now.

[0:13] Inside of the Dashboard component that you see on the other screen here, I'm going to add a console.log and a message as, "I rendered." This console.log is going to print to the console of our browser every time the Dashboard component rerenders.

[0:30] Even though React is very efficient, it's only going to change the DOM nodes that actually change from state or props from our parent component. It can still take some time to handle that rerender. Over time, with many rerenders, you're going to see a slowdown in the browser.

[0:49] Notice, that on a reload, you'll see "I rendered" just one time in this browser, even though I scroll up and down, and click and move my mouse.

[1:01] Let's print to the page the X and Y coordinates of our mouse cursor within the browser. We'll have it print every time the mouse cursor moves. Let's create a custom hook that does this for us.

[1:14] We can utilize and destructure the X-Y coordinates, and throw it into the console.log here. Inside the hooks folder that I have on the left-hand side here, let's go ahead and create a useMouseFolder. Then, here, I'm going to paste in some code and walk you all through it.

[1:30] The first things first, we're going to be importing useState and useEffect from React. You can see we have this useMousePosition which we export down the bottom. A useState that is a object that has a X and Y with a null default value. Mouse position is going to be this object here and setMousePosition is the function we updated with.

[1:52] We have a function in here that we're going to mess with here in a little bit. As is right now, it's just updating the mouse position off of client X and client Y of the event.

[2:04] Then we have a useEffect that will mount whenever the component renders. It's adding an event listener of mousemove, calls the function to update the X and Y coordinates and set that in our state.

[2:19] Then, for the cleanup of this hook, it's going to remove the mousemove listener. With this in here, let's go ahead and import the useMousePosition hook into our Dashboard component.

[2:33] Let's go ahead and change that I am rendered console.log to the X and Y coordinates that we'll get from our useMousePosition. I did just import that in using the auto import.

[2:46] Then now, let's go ahead and change this to the X and Y coordinates. Do a quick save and you'll notice that we refresh and as my mouse moves, our component is constantly rerendering the new location of our mouse. I can go really fast. Everything looks fine.

[3:02] Though as you do more and more to your application, you'll see a significant slowdown and it'll decrease the performance of your application. The easiest thing we can do is go to our useMousePosition hook that we have here and utilize the function debounce from Lodash.

[3:21] The bounce does as it says. It's going to bounce the number of requests to a number that we give it of time, in milliseconds. If I wrap this de-bounce function of our update mouse position, and if I put a comment here and add a second of 100 milliseconds.

[3:39] It's not a full second. It's 100 milliseconds. Then make sure you have this installed on your application. I've already done it. It's also in the code if you're just cloning this repo. Now when we go over to our application and run, you'll notice that I can move my mouse really quickly.

[3:57] It's only when I stop for 100 milliseconds does it actually force the rerender. It's a very quick rerender and it's only when we stop. A hundred milliseconds isn't a lot of time. It's very quick, but it's significantly decreases the number of renders that is happening in my application.

[4:15] As you look across your app and you see all the many functions that you have. You're updating state constantly, especially if you're using some type of state management library like Redux, you're going to have a lot of re-renders.

[4:26] As your application grows by doing little things like adding this de-bounce, you're going to significantly decrease the number of rerenders, which as your app scales and grows, you will make it as performant as possible.

Xavier Glab
Xavier Glab
~ 2 years ago

This is what we did in our application today, haha. Wrapped Formik setValue in lodash debounce with 200ms to ensure some delay before this function updates Formik context causing a lot of the components wrapped in <Formik /> cmp to rerender. The performance improvement was dramatic.

Markdown supported.
Become a member to join the discussionEnroll Today