Discover 5 essential React utility hooks that every developer should know: usePrevious, useDebounce, useToggle, useLocalStorage, and useClickOutside. Complete with practical code examples and real-world use cases.
React's custom hooks are powerful, but beyond the usual useState
and useEffect
, there's a world of utility hooks that can dramatically simplify your components. Here are 5 game-changing utility hooks every developer should know.
Ever needed to compare current state with its previous value? usePrevious
has you covered.
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
// Usage
function Counter() {
const [count, setCount] = useState(0);
const prevCount = usePrevious(count);
return (
<div>
<p>Current: {count}, Previous: {prevCount}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
Perfect for search inputs or API calls that shouldn't fire on every keystroke.
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
}
// Usage
function SearchBox() {
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearchTerm = useDebounce(searchTerm, 300);
useEffect(() => {
if (debouncedSearchTerm) {
// Make API call here
console.log('Searching for:', debouncedSearchTerm);
}
}, [debouncedSearchTerm]);
return <input onChange={(e) => setSearchTerm(e.target.value)} />;
}
Clean up your boolean state management with this elegant hook.
function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = useCallback(() => setValue(v => !v), []);
return [value, toggle];
}
// Usage
function Modal() {
const [isOpen, toggleModal] = useToggle(false);
return (
<>
<button onClick={toggleModal}>Open Modal</button>
{isOpen && <div className="modal">Modal Content</div>}
</>
);
}
Automatically sync your state with localStorage for persistence across sessions.
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
const setValue = (value) => {
try {
setStoredValue(value);
window.localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.log(error);
}
};
return [storedValue, setValue];
}
// Usage
function Settings() {
const [theme, setTheme] = useLocalStorage('theme', 'light');
return <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Current theme: {theme}
</button>;
}
Perfect for closing modals, dropdowns, or any element when clicking outside.
function useClickOutside(ref, callback) {
useEffect(() => {
function handleClickOutside(event) {
if (ref.current && !ref.current.contains(event.target)) {
callback();
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, [ref, callback]);
}
// Usage
function Dropdown() {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef(null);
useClickOutside(dropdownRef, () => setIsOpen(false));
return (
<div ref={dropdownRef}>
<button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
{isOpen && <div className="dropdown">Dropdown content</div>}
</div>
);
}
These utility hooks solve common problems elegantly and keep your components clean. Start incorporating them into your projects, and you'll wonder how you ever lived without them. Happy coding!