Table of Contents
1. Introduction
2. Prerequisites
3. Setting Up the Project
4. Building the Custom Hook Step by Step
4.1. Creating the hook
4.2. Handling the Resize Event
4.3. Adding Debounce for Performance
5. Using the Custom Hook
6. Conclusion
1. Introduction
In the world of frontend development with React, creating reusable and efficient components is key to building successful and maintainable applications.
One scenario that you can encounter is the need to trigger specific actions based on the size of the browser window. In this tutorial, we'll delve into the process of building a custom hook in React that allows you to execute actions when the window is resized to certain sizes.
By the end of this guide, you'll not only have a powerful custom hook at your disposal but also a deeper understanding of hooks and their implementation. So let's get to it! 🙌🏼
A reminder on custom hooks…
Custom hooks in React are reusable functions that allow you to extract common logic from your components and share it across your application, thus avoiding code repetition.
They are named with the use
prefix, and they can be used to encapsulate any kind of functionality, such as managing state, fetching data, or handling side effects.
2. Prerequisites
Before we dive into building our custom hook, let's make sure we have the necessary tools and knowledge in place:
- Basic understanding of React hooks, particularly the
useEffect
hook (You can read this other article of mine if you need a refresher 🙂) - Node.js and npm (Node Package Manager) installed on your system.
3. Setting Up the Project
To get started, let's set up a new React project 🙌🏼 or you can also use an existing one where you want to implement the custom hook. We're going to create one from scratch for the purposes of this guide.
Open your terminal and run the following commands:
npm create vite@latest window-resize-hook-demo -- --template react
cd window-resize-hook-demo
npm run dev
This will create a new react project with Vite and run it, feel free to change the name if you want to 🙂
4. Building the Custom Hook Step by Step
4.1 Creating the hook
Create a “hooks” folder in the “src” folder and inside it create a file called “useWindowResize.jsx”. Technically you can place the hook wherever you want and call it whatever you want, but it's good practice to do it like this!
In the new file, let’s create our function:
export const useWindowResize = (callback, screenSize) => {
// Hook implementation
};
The useWindowResize
hook will take 2 parameters:
-
callback
: The function that you want to execute when the window size falls outside the specified range. -
screenSize
: An object containingminWidth
and/ormaxWidth
properties, we'll use them to define the range of window sizes outside of which the callback will be triggered.
4.2 Handling the Resize Event
The first step is to handle the window resize event and check whether the current window size falls outside the specified range:
import { useEffect } from 'react';
export const useWindowResize = (callback, screenSize) => {
const { minWidth, maxWidth } = screenSize;
useEffect(() => {
const handleResize = () => {
if (
(typeof maxWidth !== "undefined" && window.innerWidth > maxWidth) ||
(typeof minWidth !== "undefined" && window.innerWidth < minWidth)
) {
callback();
}
};
// add event listener
window.addEventListener("resize", handleResize);
// cleanup function
return () => {
// remove event listener
window.removeEventListener("resize", handleResize);
};
}, [callback, maxWidth, minWidth]);
};
In this step, we add the useEffect
hook because we have to add the resize
event listener to the window object so that we can determine when to execute our callback function.
We do it inside the useEffect
hook because then we can add a cleanup function to remove the event listener once the component where the custom hook is called is unmounted, otherwise the event listener will continue to be added to the window object, leading to memory leaks and/or unexpected behaviors.
We define the handleResize
function inside the useEffect
, which will be called when the event listener is triggered, that is, when the window is rezised. This function checks if the current window width is outside the specified range, if it is, the provided callback
function is executed.
Notice that we check if the maxWidth
and minWidth
are undefined, so we can make those properties optional, this way you can either pass them both or just one of them. For example, if you only pass the maxWidth
, then the callback will only execute when the window width is higher than the maxWidth
.
We also add callback
, maxWidth
and minWidth
to the useEffect
dependency array, because if, for any reason, they change, we want the code inside the useEffect
to run again to adapt to the new values.
4.3 Adding Debounce for Performance
To enhance the performance of our custom hook, we can add a debounce mechanism to the resize event listener. Debouncing prevents the callback from being executed too frequently during rapid resizing, leading to smoother performance.
We'll use the lodash.debounce
library for this purpose, that way we don’t have to install the complete lodash library just for this functionality, or if you have a project that’s already using lodash, no need to install this one.
First, install the library by running the following command:
npm install lodash.debounce
Now, import the debounce function and use it to wrap the handleResize
function:
import { useEffect } from 'react';
import debounce from 'lodash.debounce';
export const useWindowResize = (callback, screenSize) => {
const { minWidth, maxWidth } = screenSize;
useEffect(() => {
// wrap it here
const handleResize = debounce(() => {
if (
(typeof maxWidth !== "undefined" && window.innerWidth > maxWidth) ||
(typeof minWidth !== "undefined" && window.innerWidth < minWidth)
) {
callback();
}
}, 300);
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, [callback, maxWidth, minWidth]);
};
In this case I established a 300ms delay. This means that when the window is resized, it will wait for 300ms after the last window resize event to call the handleResize
function, that way we improve performance given that the function won’t be called on every second/milisecond that the window is being resized, only when it stops being resized for at least 300ms (Hopefully that made sense 😅).
5. Using the Custom Hook
With our custom hook useWindowResize
now fully developed, it's time to put it to use in our React components. Import the hook into any component where you want to trigger specific actions based on window resize events:
import { useWindowResize } from "./hooks/useWindowResize";
function App() {
const handleWindowResize = () => {
// Perform your desired actions here
console.log("Window resized outside the specified size range");
};
useWindowResize(handleWindowResize, { minWidth: 768, maxWidth: 1024 });
return (
<>
{/* Your component's content */}
</>
);
}
export default App;
In this example, the handleWindowResize
function will be executed whenever the window width falls outside the range of 768 to 1024 pixels.
You might be wondering, what’s an example situation where I might need this? 🤔 Imagine you have a page that shows a list of products and a list of filters.
On mobile window sizes, the filters are shown on a modal when the user clicks a button, but on desktop there’s no button because the filters are shown by default on the page (not on a modal).
You might think you can handle it with just CSS, show the button that opens the modal on mobile and hide it on desktop, easy peasy ✨ But what if (and I know that this is an unlikely situation, but it could happen) an user on desktop resizes the window to a mobile size, opens the modal and then resizes it back to desktop?
The button won’t show but the modal will still be open, so with the hook you could simply call a function to close the modal on desktop size and it’ll work like a charm 🙌🏼
And besides solving the issue you know have a reusable hook that you can use anywhere else in the project where you need a similar functionality 👩🏼💻
6. Conclusion
Congratulations! You've successfully built a powerful custom hook in React that enables you to execute actions when the window is resized to certain sizes. By encapsulating this functionality in a custom hook, you've created a reusable and modular piece of code that can enhance the user experience of your applications 🚀
If you have any other examples on where you could find this custom hook useful or if you have any feedback, feel free to leave a comment! 😄
Happy coding! 🤘🏼
Top comments (0)