# @react-hookz/web: an SSR-aware React hook library and the successor line to react-use

> A TypeScript library of general-purpose React hooks grouped by problem, distributed as ES modules with per-hook subpath exports, and maintained by a former react-use maintainer.

**react-hookz/web** — React hooks done right, for browser and SSR.

- Repository: https://github.com/react-hookz/web
- Website: https://react-hookz.github.io/web/
- Stars: 2,217 · Forks: 107
- Language: TypeScript
- License: MIT
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/react-hookz-web

## Built by a react-use maintainer as a deliberate successor

The repository page describes the project as "React hooks done right, for browser and SSR", and the README frames it as a spiritual successor to react-use, written by one of that library's former maintainers and linked to the react-use tracking discussion about what should come next. That lineage is the fastest way to place it. If you already have react-use in a codebase, this is the migration candidate rather than a random third option, and the README states plainly that it was built for that purpose.

The homepage is a documentation site at react-hookz.github.io/web, so the README is a map of the catalogue rather than the reference itself. Each hook name in the list links straight into its source directory under `src/`, which is a useful convention: you can read the implementation of a hook in a dozen lines instead of guessing from its name.

The topic list is narrow and honest: `browser`, `hook`, `hooks`, `react`, `react-hook`, `react-hooks`, `ssr`, and `hacktoberfest`. There is no server or Node framework positioning in there, which matches the package name and the peer dependency list. This is a browser-side hooks package, and the one non-React runtime dependency it declares, `@ver0/deep-equal`, exists to compare dependency arrays deeply for the effect hooks that need it.

## Installing it and the React range it actually supports

Installation is the ordinary one, and the README says so in as many words before giving the commands:

```shell
npm i @react-hookz/web
# or
yarn add @react-hookz/web
```

The runtime requirement is React 16.8 or later, since that is where hooks were introduced. The manifest is more specific than the README on this point: `peerDependencies` declares `react` and `react-dom` as `^16.8 || ^17 || ^18 || ^19`, so the library is expected to work across all four major lines rather than only the newest one. The development environment sits at the other end of that range, with React and React DOM pinned at 19.2.x as dev dependencies.

One more peer dependency is easy to miss. `js-cookie` at `^3.0.5` is declared as a peer rather than a direct dependency, which means it is optional at install time in the sense that npm will warn rather than fail, but any hook you use that needs it will not work until you add it yourself. Worth checking against your own dependency tree before you hit a runtime error in a component.

The README also rules out one environment outright. Because React does not support Internet Explorer, this package does not either, and the statement is there in the install section rather than buried in a compatibility matrix.

## Two import styles and the exports map that backs them

Hooks can be imported from the package root or from a dedicated subpath, and the README gives both forms side by side:

```ts
// from the root of package
import {useMountEffect} from '@react-hookz/web';
// or single hook directly
import {useMountEffect} from '@react-hookz/web/useMountEffect';
```

The recommendation is to prefer the root import when your bundler can tree-shake, since the two forms are otherwise equal. Direct subpath imports are the fallback for bundlers that cannot. The manifest explains why this works: `"type": "module"` and `"sideEffects": false` give the bundler permission to drop unused modules, and the exports map resolves both shapes, with a pattern mapping bare subpaths to `./dist/*/index.js` and a second pattern covering the explicit `.js` form.

The release history shows that this was not always smooth. Version 26.1.0 carries a bug fix titled "resolve extensionless hook subpaths", which means the extensionless import path was broken for some period and needed a dedicated patch. If you are pinning an older version, that single line is the reason to upgrade.

There is also a packaging detail from version 26.0.0: a build fix that keeps test helpers out of the published package. Related to it, the manifest restricts `"files"` to `"./dist"`, so only the compiled output ships. That is the right arrangement, and it is recent enough that it may not be reflected in older installs.

## The hook catalogue grouped by the problem it solves

The README organises the hooks into named groups, and the grouping is the most useful part of the list because it tells you which ones solve overlapping problems.

The callback group is small and specific: `useDebouncedCallback`, `useRafCallback` and `useThrottledCallback`, each described as making a passed function debounced, throttled, or called within the next animation frame while otherwise acting like `useCallback`. The lifecycle group is the largest, holding `useMountEffect`, `useUnmountEffect`, `useUpdateEffect`, `useIsMounted`, `useFirstMountState`, `useIntervalEffect`, `useTimeoutEffect`, `useDebouncedEffect`, `useThrottledEffect`, `useRafEffect`, `useRerender`, `useIsomorphicLayoutEffect`, `useConditionalEffect`, `useCustomCompareEffect`, `useDeepCompareEffect` and `useLifecycleLogger`. The state group holds `useCounter`, `useToggle`, `usePrevious`, `usePreviousDistinct`, `useList`, `useMap`, `useSet`, `useQueue`, `useValidator`, `useFunctionalState`, `useMediatedState`, `useRenderCount`, and the debounced, throttled and raf state variants plus `useControlledRerenderState` and `useDebouncedState`. A navigator group covers `useNetworkState`, `useVibrate` and `usePermission`.

Three entries deserve a closer look because they change semantics rather than just adding convenience. `useCustomCompareEffect` and `useDeepCompareEffect` let you replace React's reference-based dependency check, which is the fix for the effect that reruns on every render because an object or array literal is a new reference each time. `useIsomorphicLayoutEffect` picks `useLayoutEffect` in the browser and `useEffect` during server rendering, which is the standard way to avoid the React warning about layout effects on the server.

The final group is labelled Miscellaneous and begins with `useSyncedRef`, at which point the README material available here ends, so the rest of that group is not something you can judge from this source.

## Where the SSR promise is made concrete

Server rendering compatibility is stated in the README's opening line as a thing the library was built with in mind, and it shows up in specific decisions rather than as a claim.

The clearest one is `useIsomorphicLayoutEffect`, which exists because `useLayoutEffect` cannot run on the server. The second is the packaging. The README warns that the package ships at ESNext language level with an ES modules system, so depending on your browser target you may need to transpile it, and that every major bundler can transpile `node_modules` fully or partially. A library that claims SSR support while publishing untranspiled syntax is handing that part of the problem back to you, so read that note as a caveat rather than a footnote.

The test setup is consistent with the claim. `jsdom` appears in the dev dependencies for the browser side, and the coverage script uses the v8 provider through `@vitest/coverage-v8`, so behaviour is exercised against a simulated DOM rather than only type-checked.

The one wrinkle worth naming is a documentation inconsistency. The README describes `useDeepCompareEffect` as using the `@react-hookz/deep-equal` comparator, while the manifest's single runtime dependency is `@ver0/deep-equal` at `^2.0.1`. The package was evidently renamed or republished under a different scope at some point, and the README text kept the older name. If you are reading the README to decide how deep comparison works, the manifest is the more reliable of the two.

## Tooling, release automation and one versioning inconsistency

The build is TypeScript through a separate project file, invoked by a script named `vp`:

```bash
vp run build:clean && tsc --version && tsc --project ./tsconfig.build.json
```

`build:clean` runs `rimraf ./dist` first, and `typecheck` is a plain `tsc --noEmit`. Linting and formatting are delegated to `vp lint` and `vp fmt`, backed in the dev dependencies by oxlint and its config package, and testing is `vp test --run` over vitest 4.1.x. The TypeScript dev dependency is `^7.0.2`, which is a notable choice for a library whose entire value depends on its type declarations being accurate.

Release automation is configured through `.releaserc.json` with `semantic-release` at `^25.0.9`, and the tags confirm it works. Version 25.3.0, 26.0.0 and 26.1.0 all landed within a two-day window ending 2026-07-26, and the notes are properly written: features for `useResizeObserver` observing a chosen box model and `useMeasure` forwarding the box model to the observer and accepting a custom measurer, and one documented breaking change in 26.0.0 where `QueueMethods.remove` returns `T | undefined` instead of `T` with runtime behaviour unchanged.

Here is the inconsistency. The `package.json` in the repository declares version `24.0.4`, while the published release history runs to `v26.1.0`. Both facts are recorded, and nothing in the repository explains the gap, most likely because semantic-release writes the version into the manifest as part of publishing rather than as a committed edit. The practical consequence is small but real: do not read the manifest in the repository as the current published version. Check npm, and pin it.

The repository also carries a `CLAUDE.md` at the root alongside `CONTRIBUTING.md`, `.editorconfig`, `vite.config.ts`, two tsconfig files, a `.yarnrc.yml` and a `yarn.lock`. The presence of a contributor guide and an editor config is a mild positive for consistency. The default branch is `master` rather than `main`, which is unusual in 2026 but not a problem, and the build badge in the README already points at `master`.

## Conclusion

The library's practical strength is that it is opinionated about the browser and about server rendering, and it packages those opinions as importable hooks instead of as advice. The 16.8 through 19 peer range, the isomorphic layout effect, and the per-hook subpath exports all point the same direction. The thing to settle before adopting it is versioning: the manifest in the repository still says 24.0.4 while the published tags run to v26.1.0, so pin the npm version rather than assuming the manifest matches what you install. Start with the callback and state groups, which are the ones most teams end up rewriting by hand, and read the section on deep comparison before you assume the dependency comparisons behave like the React built-ins.

## FAQ

### What is @react-hookz/web used for?

It is a collection of general-purpose React hooks for browser applications and for code that also renders on a server. The hooks cover callbacks, lifecycle effects, state containers, and navigator APIs such as network state and permissions, and the project positions itself as a successor to react-use.

### Which React versions does @react-hookz/web support?

The manifest declares React and React DOM as peer dependencies at ^16.8 || ^17 || ^18 || ^19, and the README states the 16.8 floor in prose. A separate peer dependency on js-cookie at ^3.0.5 is needed only for the hooks that touch cookies.

### Should I import from the package root or a hook subpath?

Use the root import such as `import {useMountEffect} from '@react-hookz/web'` when your bundler supports tree-shaking, which most modern ones do. Drop to a direct subpath like `@react-hookz/web/useMountEffect` when tree-shaking is unavailable, since the exports map resolves both forms.

## Sources

- [License: MIT](https://github.com/react-hookz/web/blob/master/LICENSE)
- [Project website](https://react-hookz.github.io/web/)
- [react-hookz/web on GitHub](https://github.com/react-hookz/web)
- [README](https://github.com/react-hookz/web/blob/master/README.md)
- [Releases](https://github.com/react-hookz/web/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/react-hookz-web
