Skip to content

Content temporarily unavailable

Historical React 19 API inventory

This inventory describes the early @tanstack/redact@0.0.1 implementation. Some behavior, sizes and support labels below are outdated. See the React 19.3 audit for the September 2026 findings, confirmed gaps and intentional runtime differences. Do not use this historical table as a current parity guarantee.

Resource APIs are no longer stubs in the current experiment. The parity expansion records current resource, reducer, Suspense, error, and security coverage, plus its measured costs.

Legend

  • real — full implementation; behavior matches React closely
  • basic — simplified implementation; covers common path, may diverge on edge cases
  • stub — API exists, returns sensible no-op value (no behavior)
  • alias — re-exports another symbol (e.g., useInsertionEffect → useLayoutEffect)
  • skip — not exported; project doesn't need it (raise error if hit)

Each entry: symbol — tier — rationale / notes


react

Hooks

ExportTierNotes
useStaterealStandard, supports updater fn + lazy init
useEffectrealAsync after commit; cleanup on re-run/unmount
useLayoutEffectrealSync after DOM mutation, before paint
useRefrealStable mutable container
useMemorealDeps-based memoization
useCallbackrealAlias of useMemo(() => fn, deps)
useContextrealContext subscription with bailout
useImperativeHandlerealRef forwarding for class-like handles
useReducerrealState machine form of useState
useDebugValuestubNo-op (DevTools hook)
useIdbasicMonotonic counter, SSR-stable. Not deterministic across reorderings — but Start doesn't use it
userealPromise + Context unwrap. Needed for useAwaited
useTransitionstub[false, fn => fn()]
useDeferredValuestubIdentity
useInsertionEffectalias→ useLayoutEffect
useSyncExternalStorebasicSubscribe + getSnapshot; tearing allowed (Router uses @tanstack/react-store anyway)
useActionStatestub[initial, noop, false]
useFormStatusstub{ pending: false, data: null, method: null, action: null }
useOptimisticstub[state, fn => fn()] — no optimistic overlay

Components

ExportTierNotes
FragmentrealRenders children flat
SuspenserealBoundary with fallback; integrates with use() and thrown promises
StrictModestubRenders children; no double-invoke
ProfilerstubRenders children

Class Components

ExportTierNotes
Componentrealthis.setState, lifecycle, getDerivedStateFromError, componentDidCatch. CatchBoundary depends on this
PureComponentbasicComponent + shallow-equal shouldComponentUpdate

Element & Ref APIs

ExportTierNotes
createElementrealClassic runtime + cloneElement path
cloneElementreal
isValidElementrealUsed by Start's slotUsageSanitizer
createRefreal{ current: null }
forwardRefreal
memorealShallow compare, optional custom areEqual
lazyrealSuspense-integrated dynamic import
createContextrealDefault value, .Provider, .Consumer, displayName
startTransitionstubfn() sync

Misc

ExportTierNotes
Children.map / forEach / count / toArray / onlybasicSimple iteration over children
cachestubIdentity fn => fn (no memoization)
versionreal"19.2.3" to satisfy version checks
actstubact(fn) → await fn()

RSC-specific (server-only, unlikely to ship client)

ExportTierNotes
createServerContextskipExperimental, not used
taintUniqueValue, taintObjectReferencestubNo-op

react/jsx-runtime, react/jsx-dev-runtime

ExportTierNotes
jsx, jsxs, jsxDEVrealElement creation for modern transform
FragmentrealRe-export

react-dom

ExportTierNotes
flushSyncrealUsed by Router's Link before navigation
createPortalbasicRender children into different DOM node
findDOMNodeskipDeprecated, unused
unstable_batchedUpdatesbasicBatch within callback
preconnect, prefetchDNS, preload, preinit, preinitModule, preloadModulestubNo-op
versionreal"19.2.3"

react-dom/client

ExportTierNotes
createRootrealReturns { render, unmount }
hydrateRootrealWith event replay + per-boundary hydration + mismatch recovery

Root options we support:

  • onRecoverableError — called for hydration mismatches
  • onCaughtError / onUncaughtError — called for error boundaries
  • identifierPrefix — prefix for useId
  • nonce — for inline scripts

react-dom/server

ExportTierNotes
renderToStringrealNon-streaming SSR
renderToStaticMarkupbasicStrip hydration markers
renderToReadableStreamrealWeb Streams; signal, nonce, progressiveChunkSize, bootstrapScripts, bootstrapModules, onError
renderToPipeableStreamrealNode streams; onShellReady, onShellError, onAllReady, onError, nonce, bootstrapScripts, bootstrapModules, progressiveChunkSize
versionreal

SSR stream must:

  • Emit Suspense boundary markers compatible with our client hydration runtime
  • Support stream.allReady promise (for bot requests)
  • Inject bootstrap scripts at end of shell
  • Handle thrown promises → render fallback, continue, queue resolved subtree for later emission

react-server-dom-*/client (browser)

Not implemented directly. Start's @tanstack/react-start-rsc/flight.ts owns createFromReadableStream / createFromFetch and routes to virtual modules controlled by Start's Vite plugin. Our shim only needs to cooperate (provide real Suspense + use() integration so the deserialized tree renders).

If Start ever moves to React's real Flight wire format, we'd add:

  • createFromFetch
  • createFromReadableStream
  • encodeReply (for server actions)

Estimated cost if added later: ~3KB gzipped.


react-dom/test-utils

ExportTierNotes
actstubact(fn) → await fn()
RestskipTest utilities not needed

scheduler

Peer dep that React imports. We ship our own micro-scheduler (~200 bytes) that implements:

  • unstable_scheduleCallback(priority, fn) → queueMicrotask(fn) or setTimeout(fn, 0) based on priority tier
  • unstable_cancelCallback(handle)
  • unstable_shouldYield() → false (no time slicing)
  • unstable_now() → performance.now()

Internals (react/internals, ReactSharedInternals)

React and react-dom coordinate via ReactSharedInternals (current dispatcher, batched updates tracker). We expose a compatible shape so third-party libs that dig into internals don't crash — minimum fields:

  • H — current hook dispatcher
  • T — current transition (null)
  • S — onStartTransition callback (null)

Explicitly not supported

  • Concurrent rendering (time slicing, work loops with yield)
  • Selective hydration with priority scheduling (we do basic progressive hydration + event replay, no priority boosting beyond "the clicked boundary")
  • React DevTools protocol (DevTools won't attach)
  • React Compiler output (react/compiler-runtime — we may add a no-op c function later if needed)
  • Server Actions via Flight encodeReply (Start uses its own serverFn system)

Package layout

A single @tanstack/redact package with subpath exports. Each subpath maps to a React-shape specifier the Vite plugin (or your own bundler aliases) rewrites:

plaintext
packages/redact/
  src/
    core/                 # VDOM types + symbols (FiberTag, Hook, ReactNode, …)
    react/                # 'react'                  → @tanstack/redact
    dom/                  # 'react-dom'              → @tanstack/redact/dom
                          # 'react-dom/client'       → @tanstack/redact/dom-client
                          # 'react-dom/test-utils'   → @tanstack/redact/dom-test-utils
      features/           # opt-in features (each is index/full/stub triple)
        portal/  context/  suspense/  memo/
        forward-ref/  lazy/  class/  hydration/
    server/               # 'react-dom/server'       → @tanstack/redact/server
    scheduler/            # 'scheduler'              → @tanstack/redact/scheduler
    vite/                 # redact() Vite plugin     → @tanstack/redact/vite
  package.json            # subpath exports for all of the above + ./features/* + ./_all

Bundler aliases are wired up by the redact() Vite plugin (or manually for non-Vite bundlers). User code keeps its canonical import { useState } from 'react' — the swap happens at the bundler level, never at the source level.


Test strategy

  1. Unit tests — each hook, each export, behavioral contracts
  2. React Testing Library compatibility suite — ensure RTL works against our shim
  3. Snapshot tests against real React for identical output on common patterns
  4. Integration — run TanStack Router's existing test suite with our shim aliased in
  5. E2E — example Start app, build + hydrate, verify clickability during streaming

Size (shipped)

Numbers from pnpm size against @tanstack/redact@0.0.1. The user-facing column names are the React-shape aliases the Vite plugin sets up.

Subpathmingzipbrotli
react6.59 KB2.65 KB2.42 KB
react/jsx-runtime247 B189 B187 B
react-dom/client (full)29.65 KB10.03 KB9.11 KB
react-dom/client (nano)20.86 KB7.49 KB6.79 KB
react-dom/server12.90 KB5.09 KB4.61 KB
Client total (full: react + react-dom/client + jsx-runtime)35.81 KB12.24 KB11.07 KB

Server-side weight doesn't count toward the page-weight goal. Per-feature gzip deltas (for sizing individual feature flags) live in SAVINGS_ANALYSIS.md.