Skip to content

Why This Library ​

The Problem ​

Every React application that needs responsive behavior eventually reaches for a ResizeObserver hook. The existing solutions work, but they were designed for an earlier era of React and carry assumptions that no longer hold in React 19.

What's wrong with existing hooks? ​

Most ResizeObserver hooks in the ecosystem share these shortcomings:

  1. One observer per element. Each hook instance creates its own ResizeObserver. With 100 observed elements on a page, you get 100 observers, 100 callback closures, and 100 independent render triggers.

  2. No batching strategy. Callbacks fire synchronously during the browser's layout step. Without coordination, each resize triggers its own setState, leading to cascading renders.

  3. CJS + ESM dual publishing. Most libraries ship both CommonJS and ESM, doubling the maintenance surface and creating subtle interop issues with bundlers.

  4. No worker story. All measurement happens on the main thread. For complex layouts, this means resize callbacks compete with user interactions for main-thread time.

  5. Pre-React 19 patterns. Libraries written before React 19 cannot take advantage of startTransition, useEffectEvent, or the React Compiler's automatic memoization.

The Solution ​

@crimson_dev/use-resize-observer was built from scratch for the React 19 era:

ConcernUpstream (v10)This Library
Observer instances1 per hook1 shared pool
Render batchingNone (direct setState)rAF + startTransition
Bundle size~1.1KB gzip1.12 kB gzip
Module formatCJS + ESM dualESM only
Worker supportNoneSharedArrayBuffer + Float16Array
Multi-element hookNoneuseResizeObserverEntries
React version18.2+19.3+
TypeScript6.x types6.0 strict (isolatedDeclarations)
React CompilerNot documentedVerified safe

Design Principles ​

ESNext-First ​

We target ES2026 and let your bundler handle downleveling. This means we can implement Disposable (using / Symbol.dispose) for automatic cleanup, use Float16Array for compact worker buffers, Atomics for cross-thread dirty-flag protocols, FinalizationRegistry for GC-backed cleanup, and Math.sumPrecise() for sub-pixel normalization in the shim.

Zero Dependencies ​

The hook has exactly zero runtime dependencies. React itself is the only peer dependency. This keeps the supply chain minimal and the bundle predictable.

Strict TypeScript ​

The library compiles under the strictest possible TypeScript 6 configuration:

  • isolatedDeclarations -- every export has an explicit type
  • erasableSyntaxOnly -- no enums, no namespaces, no parameter properties
  • exactOptionalPropertyTypes -- undefined is not the same as missing

Compiler-Safe by Default ​

Every callback passed to the hook is wrapped with useEffectEvent semantics. The React Compiler can freely memoize components that use useResizeObserver without any manual useMemo or useCallback annotations.

When to choose this library

If you are on React 19.3+ and care about bundle size, render performance, or SAB-based measurement sharing with compute workers, this library is designed for you. If you need React 18 support, upstream use-resize-observer@10 (React 18.2+) remains the better choice; for React 16/17, use upstream v9.

Further Reading ​

  • Architecture -- How the shared observer pool works internally
  • Performance -- Benchmark comparisons with other hooks
  • Migration -- Step-by-step migration from the upstream use-resize-observer

Released under the MIT License.