JavaScript Development Space

10 Essential Custom React Hooks to Supercharge Your Projects

Add to your RSS feed28 January 20255 min read
10 Essential Custom React Hooks to Supercharge Your Projects

React has revolutionized web development with its declarative and component-based approach. While built-in Hooks like useState and useEffect are indispensable, custom Hooks allow developers to encapsulate reusable logic, making codebases cleaner, modular, and easier to maintain.

This article dives into 10 powerful custom React Hooks that every developer should have in their toolkit. These Hooks will optimize your workflow, improve app performance, and simplify complex logic.

Why Use Custom Hooks?

Custom Hooks make your React development process seamless by:

  • Promoting Reusability: Share logic across components with ease.
  • Enhancing Readability: Declutter your components by offloading logic to custom Hooks.
  • Improving Testability: Test Hooks independently for more robust applications.
  • Encouraging Separation of Concerns: Keep business logic separate from UI components.

1. useFetch 🎣

A custom Hook for fetching data, managing loading state, and handling errors.

Code:

jsx
1 import { useState, useEffect } from 'react';
2
3 const useFetch = (url) => {
4 const [data, setData] = useState(null);
5 const [loading, setLoading] = useState(true);
6 const [error, setError] = useState(null);
7
8 useEffect(() => {
9 const fetchData = async () => {
10 try {
11 const response = await fetch(url);
12 if (!response.ok) throw new Error('Network error');
13 const result = await response.json();
14 setData(result);
15 } catch (err) {
16 setError(err);
17 } finally {
18 setLoading(false);
19 }
20 };
21
22 fetchData();
23 }, [url]);
24
25 return { data, loading, error };
26 };
27
28 export default useFetch;

Usage:

jsx
1 const MyComponent = () => {
2 const { data, loading, error } = useFetch('https://api.example.com/data');
3
4 if (loading) return <p>Loading...</p>;
5 if (error) return <p>Error: {error.message}</p>;
6
7 return <pre>{JSON.stringify(data, null, 2)}</pre>;
8 };

2. useLocalStorage 💾

Easily sync state with the browser's localStorage.

Code:

jsx
1 import { useState } from 'react';
2
3 const useLocalStorage = (key, initialValue) => {
4 const [storedValue, setStoredValue] = useState(() => {
5 try {
6 const item = window.localStorage.getItem(key);
7 return item ? JSON.parse(item) : initialValue;
8 } catch (error) {
9 console.error(error);
10 return initialValue;
11 }
12 });
13
14 const setValue = (value) => {
15 try {
16 const valueToStore = value instanceof Function ? value(storedValue) : value;
17 setStoredValue(valueToStore);
18 window.localStorage.setItem(key, JSON.stringify(valueToStore));
19 } catch (error) {
20 console.error(error);
21 }
22 };
23
24 return [storedValue, setValue];
25 };
26
27 export default useLocalStorage;

Usage:

jsx
1 const MyComponent = () => {
2 const [name, setName] = useLocalStorage('name', 'John Doe');
3
4 return (
5 <input
6 type="text"
7 value={name}
8 onChange={(e) => setName(e.target.value)}
9 />
10 );
11 };

3. useDarkMode 🌙

Seamlessly switch between light and dark themes.

Code:

jsx
1 import { useState, useEffect } from 'react';
2
3 const useDarkMode = () => {
4 const [isDarkMode, setIsDarkMode] = useState(() =>
5 localStorage.theme === 'dark' ||
6 (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)
7 );
8
9 useEffect(() => {
10 document.documentElement.classList.toggle('dark', isDarkMode);
11 localStorage.theme = isDarkMode ? 'dark' : 'light';
12 }, [isDarkMode]);
13
14 const toggleDarkMode = () => setIsDarkMode((prev) => !prev);
15
16 return { isDarkMode, toggleDarkMode };
17 };
18
19 export default useDarkMode;

4. useWindowSize 📏

Track window dimensions for responsive design.

Code:

jsx
1 import { useState, useEffect } from 'react';
2
3 const useWindowSize = () => {
4 const [size, setSize] = useState({
5 width: window.innerWidth,
6 height: window.innerHeight,
7 });
8
9 useEffect(() => {
10 const handleResize = () => setSize({ width: window.innerWidth, height: window.innerHeight });
11 window.addEventListener('resize', handleResize);
12 return () => window.removeEventListener('resize', handleResize);
13 }, []);
14
15 return size;
16 };
17
18 export default useWindowSize;

5. useDebounce ⏳

Delay updates to optimize performance.

Code:

jsx
1 import { useState, useEffect } from 'react';
2
3 const useDebounce = (value, delay) => {
4 const [debouncedValue, setDebouncedValue] = useState(value);
5
6 useEffect(() => {
7 const handler = setTimeout(() => setDebouncedValue(value), delay);
8 return () => clearTimeout(handler);
9 }, [value, delay]);
10
11 return debouncedValue;
12 };
13
14 export default useDebounce;

6. useClickOutside 🖱️

Detect clicks outside an element (e.g., dropdowns, modals).

Code:

jsx
1 import { useEffect } from 'react';
2
3 const useClickOutside = (ref, callback) => {
4 useEffect(() => {
5 const handleClickOutside = (event) => {
6 if (ref.current && !ref.current.contains(event.target)) callback();
7 };
8
9 document.addEventListener('mousedown', handleClickOutside);
10 return () => document.removeEventListener('mousedown', handleClickOutside);
11 }, [ref, callback]);
12 };
13
14 export default useClickOutside;

7. usePrevious 🔙

Track the previous value of a state or prop.

Code:

jsx
1 import { useRef, useEffect } from 'react';
2
3 const usePrevious = (value) => {
4 const ref = useRef();
5
6 useEffect(() => {
7 ref.current = value;
8 }, [value]);
9
10 return ref.current;
11 };
12
13 export default usePrevious;

8. useOnlineStatus 📶

Monitor the user's online/offline status.

Code:

jsx
1 import { useState, useEffect } from 'react';
2
3 const useOnlineStatus = () => {
4 const [isOnline, setIsOnline] = useState(navigator.onLine);
5
6 useEffect(() => {
7 const updateOnlineStatus = () => setIsOnline(navigator.onLine);
8 window.addEventListener('online', updateOnlineStatus);
9 window.addEventListener('offline', updateOnlineStatus);
10 return () => {
11 window.removeEventListener('online', updateOnlineStatus);
12 window.removeEventListener('offline', updateOnlineStatus);
13 };
14 }, []);
15
16 return isOnline;
17 };
18
19 export default useOnlineStatus;

Usage:

jsx
1 const MyComponent = () => {
2 const isOnline = useOnlineStatus();
3
4 return <p>{isOnline ? 'Online' : 'Offline'}</p>;
5 };

9. useOnlineStatus 🌐

Knowing if the user is online or offline is crucial for apps with real-time data or offline functionality. The useOnlineStatus hook provides real-time updates of the user's network status.

Code:

jsx
1 import { useState, useEffect } from 'react';
2
3 const useOnlineStatus = () => {
4 const [isOnline, setIsOnline] = useState(navigator.onLine);
5
6 useEffect(() => {
7 const handleOnline = () => setIsOnline(true);
8 const handleOffline = () => setIsOnline(false);
9
10 window.addEventListener('online', handleOnline);
11 window.addEventListener('offline', handleOffline);
12
13 return () => {
14 window.removeEventListener('online', handleOnline);
15 window.removeEventListener('offline', handleOffline);
16 };
17 }, []);
18
19 return isOnline;
20 };
21
22 export default useOnlineStatus;

Usage:

jsx
1 const MyComponent = () => {
2 const isOnline = useOnlineStatus();
3
4 return (
5 <div>
6 <p>Status: {isOnline ? 'Online' : 'Offline'}</p>
7 </div>
8 );
9 };

It provides a seamless way to detect network changes, improving user experience in offline-first or real-time applications.

10. useTimeout 🕒

The useTimeout hook allows you to set up a timeout and clean it up automatically. It's perfect for handling delayed actions like showing or hiding a component after a specific time.

Code:

jsx
1 import { useEffect, useRef } from 'react';
2
3 const useTimeout = (callback, delay) => {
4 const timeoutRef = useRef(null);
5
6 useEffect(() => {
7 if (delay === null) return;
8
9 timeoutRef.current = setTimeout(callback, delay);
10
11 return () => clearTimeout(timeoutRef.current);
12 }, [callback, delay]);
13
14 return () => clearTimeout(timeoutRef.current);
15 };
16
17 export default useTimeout;

Usage:

jsx
1 const MyComponent = () => {
2 const showMessage = () => alert('Timeout triggered!');
3 const clearTimeout = useTimeout(showMessage, 5000);
4
5 return (
6 <button onClick={clearTimeout}>Cancel Timeout</button>
7 );
8 };

It simplifies managing timeouts in functional components, reducing the risk of memory leaks or stale references.

Final Thoughts

These 10 custom React Hooks will not only save you time but also make your code more efficient and maintainable. Whether you're handling data fetching, managing themes, or optimizing performance, these Hooks are essential for modern React development.

Start using these Hooks today, or create your own to tackle unique challenges! 🚀

JavaScript Development Space

© 2025 JavaScript Development Space - Master JS and NodeJS. All rights reserved.