iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Custom Hooks

A custom hook is any function whose name starts with use that calls other hooks. It’s how teams extract reusable stateful logic without HOCs or render-props.

Three production-grade custom hooks

EXAMPLE
import { useState, useEffect, useRef, useCallback } from 'react';

// 1) useDebounce — delays a value until typing pauses
export function useDebounce(value, ms = 300) {
    const [debounced, setDebounced] = useState(value);
    useEffect(() => {
        const t = setTimeout(() => setDebounced(value), ms);
        return () => clearTimeout(t);
    }, [value, ms]);
    return debounced;
}

// 2) useLocalStorage — synced state across tabs
export function useLocalStorage(key, initial) {
    const [value, setValue] = useState(() => {
        try { return JSON.parse(localStorage.getItem(key)) ?? initial; }
        catch { return initial; }
    });
    useEffect(() => {
        localStorage.setItem(key, JSON.stringify(value));
    }, [key, value]);
    useEffect(() => {
        function onStorage(e) {
            if (e.key === key) setValue(JSON.parse(e.newValue));
        }
        window.addEventListener('storage', onStorage);
        return () => window.removeEventListener('storage', onStorage);
    }, [key]);
    return [value, setValue];
}

// 3) useFetch — async data with abort on dep change / unmount
export function useFetch(url) {
    const [state, setState] = useState({ data: null, error: null, loading: true });
    useEffect(() => {
        const ctrl = new AbortController();
        setState(s => ({ ...s, loading: true }));
        fetch(url, { signal: ctrl.signal })
            .then(r => r.json())
            .then(data => setState({ data, error: null, loading: false }))
            .catch(err => {
                if (err.name !== 'AbortError') setState({ data: null, error: err, loading: false });
            });
        return () => ctrl.abort();
    }, [url]);
    return state;
}

Why it matters

Three rules for custom hooks: 1) name starts with use (so the linter checks dep arrays); 2) they obey the same rules of hooks; 3) ideally pure, with no global side effects on first call.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
function useToggle(initial = false) {
    const [on, setOn] = useState(initial);
    return [on, () => setOn(o => !o)];
}
Try it Yourself »

Discussion

Loading…