useDebugValue adds a label to custom hooks in React DevTools, making debugging easier.
Basic Usage
tsximport { useDebugValue, useState, useEffect } from 'react'; function useOnlineStatus() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { const handleOnline = () => setIsOnline(true); const handleOffline = () => setIsOnline(false); window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); // Shows "OnlineStatus: Online" or "OnlineStatus: Offline" in DevTools useDebugValue(isOnline ? 'Online' : 'Offline'); return isOnline; }
Deferred Formatting
For expensive formatting, pass a format function as the second argument:
tsxfunction useUser(userId: string) { const user = useFetchUser(userId); // Format function only called when DevTools is open useDebugValue(user, (user) => { if (!user) return 'Loading...'; return `${user.name} (${user.role})`; }); return user; }
Best Practices
✅ Use for:
- Custom hooks in shared libraries
- Complex hooks where the internal state isn't obvious
- Hooks that would benefit from a human-readable label
❌ Don't use for:
- Simple hooks where the value is obvious
- Every custom hook (adds noise)
- Production performance-critical code (though impact is minimal)
Example: Date Formatting Hook
tsxfunction useFormattedDate(date: Date, locale = 'en-US') { const formatted = useMemo(() => { return new Intl.DateTimeFormat(locale, { dateStyle: 'full', timeStyle: 'short' }).format(date); }, [date, locale]); useDebugValue(date, (d) => d.toISOString()); return formatted; }
In DevTools, you'll see: FormattedDate: "2026-01-14T10:30:00.000Z"