Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions compiler/docs/EXPERIMENTAL_STRUCTURED_HOOKS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Experimental Structured Hooks

This experiment asks a narrow but radical question:

> Are the Rules of Hooks describing a semantic truth about React, or mostly a consequence of the current cursor-based runtime representation of hook state?

## Hypothesis

Today, hook identity is derived from call order. That makes conditional hooks unsafe, because React walks a linked list of hook cells in render order and expects the same sequence on every render.

The React Compiler already understands control flow well enough to prove much stronger properties than the runtime can observe. That suggests a different experiment: for a tiny structured subset, lower hook identity to explicit static keys instead of positional cursors.

If that works, then some currently forbidden programs stop being fundamentally impossible. They are only incompatible with the current representation.

## First Prototype

The first branch prototype started as a tiny runtime-only model, then added a React-hosted layer that keeps the same keyed cells behind one real React hook call.

- keyed state cells
- keyed memo cells
- dormant branch-local cells stay stored while the branch is hidden
- duplicate keys in one render throw
- changing a key from one hook kind to another throws
- a React-hosted variant can rerender through a single top-level hook

This is enough to prove the core claim: branch-local hook state can survive disappear/reappear cycles when identity is stable and explicit. More importantly, it shows a plausible compiler target that still obeys React's runtime contract by collapsing the experiment to one actual hook call.

There is now also a tiny compiler seam for that target. When `enableEmitStructuredHooks` is enabled and a function uses `'use structured hooks'`, the compiler can lower a deliberately small subset into `experimental_useStructuredHooks(...)`:

- `useState()` / `React.useState()` in direct variable initializers
- `useMemo()` / `React.useMemo()` in direct variable initializers with inline zero-argument callbacks and literal dependency arrays
- structured control flow built from blocks, `if`, variable declarations, expression statements, and returns

Anything outside that subset currently errors on purpose. The experiment is trying to prove the representation shift first, not pretend arbitrary conditional hooks are solved.

## Why It Matters

If this line of research holds, a future compiler experiment could target a small opt-in subset such as:

- statically provable `if` branches
- direct hook calls with compiler-assigned stable keys
- carefully widened loop or switch forms once key assignment and dormant-cell semantics stay clear

That would not abolish the Rules of Hooks for ordinary JavaScript. It would show that React can carve out a new space where some of those rules become compilation constraints instead of universal language laws.
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ export type PluginOptions = Partial<{
*/
enableReanimatedCheck: boolean;

/**
* Experimental research surface. When enabled, functions annotated with
* 'use structured hooks' may be lowered to a single runtime hook call.
*/
enableEmitStructuredHooks: boolean;

/**
* The minimum major version of React that the compiler should emit code for. If the target is 19
* or higher, the compiler emits direct imports of React runtime APIs needed by the compiler. On
Expand Down Expand Up @@ -317,6 +323,7 @@ export const defaultOptions: ParsedPluginOptions = {
return filename.indexOf('node_modules') === -1;
},
enableReanimatedCheck: true,
enableEmitStructuredHooks: false,
customOptOutDirectives: null,
target: '19',
};
Expand Down
Loading