react-next-hooks
v0.1.0
Published
A collection of SSR-safe React hooks for React and Next.js apps
Maintainers
Readme
react-next-hooks
A collection of SSR-safe React hooks, written in TypeScript. Works in plain React (Vite, CRA) and Next.js (App Router and Pages Router) — every hook guards against window/document access on the server.
Installation
npm install react-next-hooksRequires React 17+.
Hooks
| Hook | Description |
| --- | --- |
| useLocalStorage | useState persisted to localStorage, synced across tabs |
| useDebounce | Debounce a changing value |
| useToggle | Boolean state with stable toggle/set |
| useMediaQuery | Track a CSS media query (SSR fallback supported) |
| useClickOutside | Detect clicks outside an element |
| usePrevious | Value from the previous render |
| useFetch | Declarative fetch with loading/error/refetch and abort |
| useWindowSize | Track window dimensions |
| useInterval | Declarative setInterval, pausable |
| useCopyToClipboard | Copy text with transient copied feedback |
| useIsomorphicLayoutEffect | useLayoutEffect without SSR warnings |
Usage
useLocalStorage
const [theme, setTheme, removeTheme] = useLocalStorage('theme', 'light');
setTheme('dark');
setTheme((prev) => (prev === 'dark' ? 'light' : 'dark'));useDebounce
const [query, setQuery] = useState('');
const debouncedQuery = useDebounce(query, 300);
useEffect(() => {
if (debouncedQuery) search(debouncedQuery);
}, [debouncedQuery]);useToggle
const [open, toggle, setOpen] = useToggle(false);useMediaQuery
// Second arg is the value returned during SSR (default false)
const isDesktop = useMediaQuery('(min-width: 1024px)');useClickOutside
const ref = useClickOutside<HTMLDivElement>(() => setOpen(false));
return <div ref={ref}>Dropdown</div>;usePrevious
const count = useSelector(selectCount);
const prevCount = usePrevious(count); // undefined on first renderuseFetch
const { data, error, loading, refetch } = useFetch<User[]>('/api/users');
// Pass null to skip (dependent requests)
const { data: posts } = useFetch(user ? `/api/users/${user.id}/posts` : null);useWindowSize
const { width, height } = useWindowSize(); // { 0, 0 } during SSRuseInterval
useInterval(() => setCount((c) => c + 1), running ? 1000 : null);useCopyToClipboard
const { copy, copied } = useCopyToClipboard();
<button onClick={() => copy(text)}>{copied ? 'Copied!' : 'Copy'}</button>;useIsomorphicLayoutEffect
// Drop-in replacement for useLayoutEffect in Next.js
useIsomorphicLayoutEffect(() => {
measure();
}, []);Next.js notes
All hooks are safe to import in Server Components files that pass them to Client Components, but hooks must run inside components marked 'use client'. SSR behavior: useLocalStorage returns the initial value on the server, useMediaQuery returns its serverFallback, and useWindowSize returns { width: 0, height: 0 }, then all update after hydration — no mismatch warnings.
Development
npm install
npm test # vitest
npm run build # ESM + CJS + .d.ts to dist/License
MIT
