Open Source
React
React internals

Hidden React Features & Internal APIs

5 min read
F
Fahd
Author
Hidden React Features & Internal APIs

React developers occasionally stumble upon cryptic APIs like React.__CLIENT_INTERNALS_DO_NOT_USE or warnings about "invalid hook calls."
These are internal APIs - powerful, unsupported, and intentionally hidden. Let’s explore why they exist, how React uses them, and why you should avoid them.

What Are Internal APIs? (It’s Not Just React)

Internal APIs are framework mechanics that:

  • Handle critical low-level operations (rendering, state management)
  • Are unstable by design (implementation can change without warning)
  • Lack documentation and TypeScript support
// (Don’t actually use this!) const internals = React.__CLIENT_INTERNALS_DO_NOT_USE__; console.log(internals.H); // react internals have weird Letters so it becomes harder to use // Output: { current: null } (This dispatches hooks during render)

Other frameworks do this too

Why React Hides APIs: The Stability Tradeoff

  1. Freedom to Refactor
    React’s core team can optimize internals (like the Fiber architecture) without breaking user code.
// React 16 vs 18 Fiber node structure (simplified) // ---------- // React 16 (Stack Reconciler) class FiberNode { tag: WorkTag; //determines whether it’s a functional component, class component, or host element. stateNode: any; // Holds the class instance or DOM node effectTag: SideEffectTag; // Marks the type of side effects (update, deletion, etc.) // ... } // React 18 (Fiber Reconciler) class FiberNode { tag: WorkTag; lanes: Lane; // Priority tracking for concurrent mode flags: Flags; // Replaces effectTag, Tracks side effects in a more optimized way. // ... }

If these structures were public, every React upgrade would risk breaking apps that relied on internal shapes.

  1. Preventing Footguns
    If you are not familiar with the term "footgun". it means you basically have a gun, then you use it to shoot yourself in the foot.
    Internal APIs often assume specific calling contexts. For example:
// ⚠️ Hypothetical misuse of internal API function DangerousComponent() { // Accessing dispatcher outside render phase = undefined behavior const dispatcher = React.__CLIENT_INTERNALS_DO_NOT_USE__.H.current; // extracting the hook dispatcher const [state, setState] = dispatcher.useState(); // getting the useState function out of the dipatcher ourselves // ... }

This could break React’s render cycle tracking, leading to stale state or memory leaks.

Case Study: How Hooks Actually Work (The Dispatcher)

Hooks like useState and useEffect rely on a dispatcher an internal system that:

  • Tracks component instances
  • Manages hook call order
  • Enforces rules (e.g., "no hooks in conditionals")

This is a snippet from the react source code (on top of my mind and using deepseek, not copied so don't rely on it too much)

let currentDispatcher = null; function resolveDispatcher() { if (currentDispatcher === null) { throw Error('Hooks can only be called inside a component'); } return currentDispatcher; } const ReactCurrentDispatcher = { current: null, }; // Your useState is actually: function useState(initialState) { const dispatcher = resolveDispatcher(); return dispatcher.useState(initialState); } // During render, React swaps dispatchers: function renderComponent(Component) { ReactCurrentDispatcher.current = MyRendererDispatcher; const output = Component(props); ReactCurrentDispatcher.current = null; return output; }

takeaway: Hooks are dispatcher-dependent. If you tamper with ReactCurrentDispatcher, you’ll break React’s ability to track state.

The Rule of Thumb

In English, the phrase rule of thumb refers to an approximate method for doing something, based on practical experience rather than theory.

If an API:

  • Is undocumented
  • Has DO_NOT_USE, internal, or unstable in its name
  • Triggers a console warning

Treat it like a radioactive API - useful for React maintainers, dangerous for everyone else.

is it always internal?

nope, some of the React internals APIs came public after a while

  • createRoot (was unstable_createRoot before React 18)
  • useId Hook (originally part of React’s server rendering internals, to see the change check React PR #22644)

These follow rigorous testing and RFCs. Your app’s abstractions should too.

Final Thought: Want to dive deeper? Study React’s official codebase - but treat it as a learning resource, not a toolbox.
pssstt.. Preact uses internal APIs in their codebase, you shouldn't anyways ;) .. I fear discussing wih dan abramov