49+ examples • All built-in hooks + React 19 • Custom hook patterns
const [count, setCount] = useState(0);const [user, setUser] = useState<User | null>(null);const [items, setItems] = useState<string[]>([]);setCount(prev => prev + 1);setUser({ ...user, name: 'Alice' });setItems(prev => [...prev, newItem]);setItems(prev => prev.filter(i => i.id !== id));const [state, setState] = useState(() => {
return expensiveComputation();
});useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);useEffect(() => {
fetchData();
}, []);useEffect(() => {
const id = setInterval(tick, 1000);
return () => clearInterval(id);
}, []);useEffect(() => {
const ctrl = new AbortController();
fetch(url, { signal: ctrl.signal })
.then(r => r.json())
.then(setData);
return () => ctrl.abort();
}, [url]);useEffect(() => {
const handler = (e: KeyboardEvent) => {
if (e.key === 'Escape') setOpen(false);
};
window.addEventListener('keydown', handler);
return () => window.removeEventListener('keydown', handler);
}, []);const inputRef = useRef<HTMLInputElement>(null);
// <input ref={inputRef} />
// inputRef.current?.focus();const prevValue = useRef(value);
useEffect(() => {
prevValue.current = value;
}, [value]);const isMounted = useRef(true);
useEffect(() => {
return () => { isMounted.current = false; };
}, []);const timerRef = useRef<number>();
timerRef.current = window.setTimeout(fn, 1000);
// clearTimeout(timerRef.current);const sorted = useMemo(
() => items.sort((a, b) => a.name.localeCompare(b.name)),
[items]
);const filtered = useMemo(
() => users.filter(u => u.name.includes(query)),
[users, query]
);const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []);const handleSubmit = useCallback((data: FormData) => {
api.save(id, data);
}, [id]);// React 19: useCallback/useMemo often unnecessary
// React Compiler auto-memoizesconst ThemeContext = createContext<'light' | 'dark'>('light');function App() {
return (
<ThemeContext.Provider value="dark">
<Child />
</ThemeContext.Provider>
);
}const theme = useContext(ThemeContext);// Custom hook pattern
function useTheme() {
const ctx = useContext(ThemeContext);
if (!ctx) throw new Error('useTheme must be inside ThemeProvider');
return ctx;
}type Action =
| { type: 'increment' }
| { type: 'decrement' }
| { type: 'reset'; payload: number };
function reducer(state: number, action: Action): number {
switch (action.type) {
case 'increment': return state + 1;
case 'decrement': return state - 1;
case 'reset': return action.payload;
}
}const [state, dispatch] = useReducer(reducer, 0);dispatch({ type: 'increment' });
dispatch({ type: 'reset', payload: 0 });const [state, dispatch] = useReducer(reducer, initialArg, init);const id = useId();
// <label htmlFor={id}>Name</label>
// <input id={id} />const [isPending, startTransition] = useTransition();
startTransition(() => {
setSearchResults(filterData(query));
});const deferredQuery = useDeferredValue(query);
const results = useMemo(
() => filterItems(deferredQuery),
[deferredQuery]
);useSyncExternalStore(
store.subscribe,
store.getSnapshot,
store.getServerSnapshot
);useInsertionEffect(() => {
const style = document.createElement('style');
style.textContent = css;
document.head.appendChild(style);
return () => style.remove();
}, [css]);const [state, formAction, isPending] = useActionState(
async (prev, formData) => {
const result = await saveUser(formData);
return result;
},
initialState
);const [optimisticName, setOptimistic] = useOptimisticState(name);
// Instantly update UI before server responds
setOptimistic('New Name');// use() can read promises and context
const data = use(fetchPromise);
const theme = use(ThemeContext);// ref as prop (no forwardRef needed in React 19)
function Input({ ref, ...props }) {
return <input ref={ref} {...props} />;
}function useLocalStorage<T>(key: string, initial: T) {
const [value, setValue] = useState<T>(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initial;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue] as const;
}function useDebounce<T>(value: T, delay: number): T {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debounced;
}function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const ctrl = new AbortController();
fetch(url, { signal: ctrl.signal })
.then(r => r.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
return () => ctrl.abort();
}, [url]);
return { data, loading, error };
}function useMediaQuery(query: string): boolean {
const [matches, setMatches] = useState(
() => window.matchMedia(query).matches
);
useEffect(() => {
const mql = window.matchMedia(query);
const handler = (e: MediaQueryListEvent) => setMatches(e.matches);
mql.addEventListener('change', handler);
return () => mql.removeEventListener('change', handler);
}, [query]);
return matches;
}function useOnClickOutside(
ref: RefObject<HTMLElement>,
handler: () => void
) {
useEffect(() => {
const listener = (e: MouseEvent) => {
if (!ref.current?.contains(e.target as Node)) handler();
};
document.addEventListener('mousedown', listener);
return () => document.removeEventListener('mousedown', listener);
}, [ref, handler]);
}// ❌ Don't mutate state directly
state.items.push(item);
// ✅ Create new reference
setState({ ...state, items: [...state.items, item] });// ❌ Stale closure
useEffect(() => {
setInterval(() => console.log(count), 1000);
}, []);
// ✅ Use ref for latest value
const countRef = useRef(count);
countRef.current = count;// ❌ Unnecessary effect
useEffect(() => {
setFullName(first + ' ' + last);
}, [first, last]);
// ✅ Derive during render
const fullName = first + ' ' + last;// Rules of Hooks:
// 1. Only call at top level (no if/for/nested)
// 2. Only call in React functions or custom hooks
// 3. Custom hooks must start with 'use'// Conditional rendering with hooks
const Component = ({ show }: { show: boolean }) => {
// ❌ if (show) { const [x] = useState(0); }
const [x] = useState(0); // ✅ always call
if (!show) return null;
return <div>{x}</div>;
};Made with ♥ by Kas Developer Tools