@arses_ui/use-everything-hooks
v0.1.2
Published
Tiny, tree-shakeable, SSR-safe React hooks for React 18+ and Next.js (App Router & Pages Router).
Maintainers
Readme
@arses_ui/use-everything-hooks
Small, tree-shakeable, SSR-safe React hooks for React 18/19 and Next.js (App Router + Pages Router). Written in strict TypeScript, zero dependencies, ~4.5 kB gzipped for everything (you only ship what you import).
npm i @arses_ui/use-everything-hooksThe bundle ships with a "use client" directive, so you can import hooks straight into Client Components in the Next.js App Router with no wrapper files.
Hooks
| Category | Hooks |
| --- | --- |
| Timing | useDebounce, useDebouncedCallback, useThrottle, useThrottledCallback, useInterval, useTimeout |
| Viewport | useInfiniteScroll, useIntersectionObserver, useInView, useMediaQuery, useWindowSize |
| Browser | useEventListener, useClickOutside, useOnlineStatus, useCopyToClipboard |
| Storage | useLocalStorage, useSessionStorage |
| Utilities | useToggle, usePrevious, useMounted, useIsClient, useLatest, useEventCallback, useIsomorphicLayoutEffect |
Examples
Debounced search
const [query, setQuery] = useState('');
const debounced = useDebounce(query, 300);
useEffect(() => { search(debounced); }, [debounced]);Debounced / throttled callbacks
const save = useDebouncedCallback((text: string) => api.save(text), 500, { maxWait: 2000 });
save.flush(); // run now
save.cancel(); // drop it
save.isPending();
const onScroll = useThrottledCallback(() => track(), 100);Both have a stable identity, always call the latest closure, and cancel on unmount.
Infinite scroll
const { sentinelRef } = useInfiniteScroll({
onLoadMore: fetchNextPage, // may return a Promise
hasMore: hasNextPage,
isLoading: isFetchingNextPage, // optional (React Query, SWR, ...)
rootMargin: '300px', // prefetch before the user reaches the end
});
return <>{items.map(renderItem)}<div ref={sentinelRef} /></>;- Single sentinel +
IntersectionObserver: no scroll listeners, no layout reads. - Never fires concurrently; keeps loading until the viewport is full; failed loads aren't retried in a loop (
onError). - Custom scroll container:
useInfiniteScroll({ root: containerEl, ... }).
Visibility
const [ref, inView] = useInView<HTMLDivElement>({ once: true }); // fewest re-renders
const { ref, isIntersecting, entry } = useIntersectionObserver({ threshold: [0, .5, 1] });Storage (hydration-safe, synced across tabs)
const [theme, setTheme, resetTheme] = useLocalStorage<'light' | 'dark'>('theme', 'light');
setTheme((t) => (t === 'light' ? 'dark' : 'light'));Others
const isDesktop = useMediaQuery('(min-width: 1024px)', /* SSR default */ true);
const ref = useClickOutside<HTMLDivElement>(() => setOpen(false), { enabled: open });
useEventListener('keydown', (e) => e.key === 'Escape' && close());
const [copied, copy] = useCopyToClipboard();
const { width } = useWindowSize();Performance design
- Tree-shakeable: ESM + CJS,
"sideEffects": false, one module per hook. - Shared IntersectionObserver pool: any number of
useInView/useIntersectionObserver/useInfiniteScrollconsumers with the same options share one observer. useSyncExternalStorefor storage, media queries, online status and window size: concurrent-rendering safe, no tearing, nouseEffect+setStateflash.- One shared resize listener (rAF-coalesced) for all
useWindowSizeconsumers. - Stable identities for every returned function, so memoized children don't re-render.
- No work when idle:
useDebounceschedules no timer if the value didn't change; observers/listeners are only attached whenenabled. - Snapshots are primitives (raw storage string) with memoized parsing: no re-render loops from fresh objects.
SSR / Next.js notes
- Nothing touches
window/documentat import or during render. Server snapshots are explicit, so hydration never mismatches (e.g.useLocalStoragerendersinitialValuefirst, then the stored value). - Use
useIsClient()for client-only UI, anduseIsomorphicLayoutEffectinstead ofuseLayoutEffect. - Requires React >= 18 (uses
useSyncExternalStore).
you can message us in:
arsestech.ir
for any reports or problems
