Custom Hooks
Building reusable logic, naming conventions, composition patterns, and testing.
Overview
Custom hooks extract component logic into reusable functions starting with "use".
Key Concepts
- Naming Convention — Must start with "use"
- Single Responsibility — One hook per concern
- Composition — Hooks can call other hooks
- Testing — Test hooks with @testing-library/react-hooks
- Sharing Logic — Share stateful logic between components
Code Examples
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch {
return initialValue;
}
});
useEffect(() => {
window.localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
// Usage
function SearchInput() {
const [search, setSearch] = useLocalStorage('search', '');
const debouncedSearch = useDebounce(search, 300);
return (
<input
value={search}
onChange={e => setSearch(e.target.value)}
placeholder="Search..."
/>
);
}
Practice
Create a useFetch hook with caching, retry logic, and abort controller support.