Practical Custom Hooks Examples
In this guide, we will build three highly practical, production-ready custom hooks to handle data fetching, local storage persistence, and search input debouncing.
1. Custom Hook: useFetch
This hook manages network request state, including loading progress and errors:
import { useState, useEffect } from "react";
export function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let isMounted = true;
setLoading(true);
fetch(url)
.then((res) => {
if (!res.ok) throw new Error("Network response was not ok");
return res.json();
})
.then((jsonData) => {
if (isMounted) {
setData(jsonData);
setError(null);
}
})
.catch((err) => {
if (isMounted) {
setError(err.message);
}
})
.finally(() => {
if (isMounted) {
setLoading(false);
}
});
return () => {
isMounted = false; // Cancel state updates on unmount
};
}, [url]);
return { data, loading, error };
}2. Custom Hook: useLocalStorage
This hook synchronizes a state variable with the browser local storage automatically:
import { useState, useEffect } from "react";
export function useLocalStorage(key, initialValue) {
// Read existing value from local storage or fallback to initialValue
const [value, setValue] = useState(() => {
try {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
} catch (e) {
return initialValue;
}
});
// Synchronize changes to local storage
useEffect(() => {
try {
localStorage.setItem(key, JSON.stringify(value));
} catch (e) {
console.error("Local storage sync error:", e);
}
}, [key, value]);
return [value, setValue];
}3. Custom Hook: useDebounce
Use this hook to delay processing rapid state changes (for example, waiting for a user to finish typing in a search bar before triggering an API request):
import { useState, useEffect } from "react";
export function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
// Set a timeout to update the debounced value
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
// Clean up the timeout if the value changes before delay expires
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}Published on Last updated: