v2.1.051 new hooks in this release
Hooks for the parts of React you keep rewriting_
91 typed hooks for state, async data, realtime connections, gestures and browser APIs. Each one is SSR-safe, cleans up after itself and ships with zero dependencies.
$ npm install @zenuilabs/react-hooks
this-page.live
rec 00:00Start from the problem.
Hooks are grouped by what you are trying to do, not by which browser API they wrap.
- 01StateuseBroadcastState useCounter useLocalStorage useMap12
- 02Async & DatauseAsync useAsyncRetry useCachedFetch useFetch7
- 03RealtimeuseEventSource usePolling useWebSocket3
- 04PerformanceuseDebounce useDebouncedCallback useThrottle useThrottledCallback6
- 05Events & DOMuseClickOutside useEvent useHover useIntersection15
- 06InteractionuseDraggable useDrop useDropArea useFocusTrap9
- 07Browser & DeviceuseBattery useBreakpoint useColorScheme useEyeDropper18
- 08MediauseAudio useFullscreen useSpeechSynthesis useVideo4
- 09Time & MotionuseAnimationFrame useCountdown useInterval useSpringValue6
- 10UtilitiesuseCookie useCopyToClipboard useDeepCompareEffect useDocumentTitle11
Delete the effect you wrote last sprint.
Persisting a value sounds like one line of work. In practice it needs a server check, a parse guard, a write effect and a listener for other tabs. The hook does all four, and it is tested in Node, so it never breaks a server render.
30
By hand, lines
6
With the hook, lines
use-theme.ts
import {useEffect, useState} from 'react';
function useTheme() {
const [theme, setTheme] = useState(() => {
if (typeof window === 'undefined') return 'light';
try {
const raw = window.localStorage.getItem('theme');
return raw ? JSON.parse(raw) : 'light';
} catch {
return 'light';
}
});
useEffect(() => {
try {
window.localStorage.setItem('theme', JSON.stringify(theme));
} catch {}
}, [theme]);
useEffect(() => {
const onStorage = (event: StorageEvent) => {
if (event.key !== 'theme' || event.newValue === null) return;
setTheme(JSON.parse(event.newValue));
};
window.addEventListener('storage', onStorage);
return () => window.removeEventListener('storage', onStorage);
}, []);
return [theme, setTheme] as const;
}Where most people start.
All hooksEvents & DOMBasicuseClickOutsideCall a function when the user presses anywhere outside an element. Use it to close menus, popovers and dialogs.StateBasicuseCounterHold a number with stable increment, decrement, set and reset helpers. Optional min, max and step options keep it inside a range, which suits quantity pickers and pagers.PerformanceBasicuseDebounceReturn a copy of a value that only updates after it has stopped changing for a set time. Use it to wait for the user to pause before searching or saving.Async & DataIntermediateuseFetchFetch JSON from a URL and track data, loading and error. It aborts stale requests when the URL changes or the component unmounts, and can refetch on demand.StateIntermediateuseLocalStorageKeep a piece of state in localStorage as JSON, synced across components and browser tabs. Use it for preferences and drafts that should survive a reload.StateIntermediateuseSessionStorageKeep a piece of state in sessionStorage as JSON. The value survives a reload but is cleared when the tab closes, which suits wizard steps and temporary form input.PerformanceIntermediateuseThrottleReturn a copy of a fast-changing value that updates at most once per interval. Use it for scroll positions, pointer coordinates and other values that change many times a second.StateBasicuseToggleHold a boolean with stable helpers to flip it, set it and reset it. Use it for modals, menus and on or off settings.Events & DOMBasicuseWindowSizeTrack the inner width and height of the browser window. Use it for layout decisions that CSS media queries cannot express.
New in 2.1: 51 hooks for harder problems.
See what changed- useBroadcastStateStateAdvanced
- useCachedFetchAsync & DataAdvanced
- useDraggableInteractionAdvanced
- useFocusTrapInteractionAdvanced
- useHotkeysInteractionAdvanced
- useInfiniteScrollAsync & DataAdvanced
- useOptimisticStateAsync & DataAdvanced
- usePollingRealtimeAdvanced
- useRovingFocusInteractionAdvanced
- useSpringValueTime & MotionAdvanced
- useStateHistoryStateAdvanced
- useStateMachineStateAdvanced
- useTaskQueueAsync & DataAdvanced
- useVirtualListPerformanceAdvanced
- useWebSocketRealtimeAdvanced
- useWorkerPerformanceAdvanced
- useAnimationFrameTime & MotionIntermediate
- useBreakpointBrowser & DeviceIntermediate
- useColorSchemeBrowser & DeviceIntermediate
- useCountdownTime & MotionIntermediate
- useDebouncedCallbackPerformanceIntermediate
- useDeepCompareEffectUtilitiesIntermediate
- useEventCallbackUtilitiesIntermediate
- useEventSourceRealtimeIntermediate
- useFileDialogBrowser & DeviceIntermediate
- useIsomorphicLayoutEffectUtilitiesIntermediate
- useMapStateIntermediate
- useMutationObserverEvents & DOMIntermediate
- usePermissionBrowser & DeviceIntermediate
- useQueueStateIntermediate
- useResizeObserverEvents & DOMIntermediate
- useScriptUtilitiesIntermediate
- useScrollSpyEvents & DOMIntermediate
- useSetStateIntermediate
- useSpeechSynthesisMediaIntermediate
- useStopwatchTime & MotionIntermediate
- useSwipeInteractionIntermediate
- useTextSelectionEvents & DOMIntermediate
- useThrottledCallbackPerformanceIntermediate
- useWakeLockBrowser & DeviceIntermediate
- useWhyDidYouUpdateUtilitiesIntermediate
- useBatteryBrowser & DeviceBasic
- useDocumentTitleUtilitiesBasic
- useEyeDropperBrowser & DeviceBasic
- useIsClientUtilitiesBasic
- useIsMountedUtilitiesBasic
- useLatestUtilitiesBasic
- useReducedMotionBrowser & DeviceBasic
- useShareBrowser & DeviceBasic
- useTextareaAutosizeInteractionBasic
- useTimeAgoTime & MotionBasic