The React Compiler performs multiple validation passes that work on the High-level Intermediate Representation (HIR) and ReactiveFunction data structures. These validations ensure that the code respects React’s paradigms related to hooks, memoization, effects, and state management. Additionally, validations check that compiler transformations preserve semantics and enforce usage restrictions that prevent infinite renders, unintended side effects, or behavioral inconsistencies.
Validation checks are critical for catching:
Validation errors are recorded as structured diagnostics with category, reason, location, and suggestions, facilitating great developer feedback.
Validation typically operates by traversing the HIR function bodies. Errors detected during validation are reported by pushing CompilerDiagnostic objects into the compiler Environment.
CompilerError aggregates multiple CompilerDiagnostic entries, representing reported issues, which associate an error category, reason, detailed explanation, source location, and severity levels (Error, Warning, Hint, Off).Environment.recordError with diagnostics.Sources:
The validateExhaustiveDependencies pass verifies that all manual dependency arrays (e.g., passed to useEffect, useMemo, useCallback) correctly and exhaustively list all reactive values referenced within memoized or effect functions. This ensures consistency between manual and inferred dependencies and prevents introducing bugs where auto-memoization would change behavior.
Key Details:
collectDependencies to find every reactive identifier referenced inside memo functions or effects.StartMemoize / FinishMemoize instructions.Sources:
React forbids reading or writing ref.current during the render, as refs represent mutable references that should not influence render output.
How validateNoRefAccessInRender works:
RefAccessType states for identifiers, including None, Ref, RefValue, Nullable, and more complex Structure kinds..current on useRef or identified ref values during the render phase.ref.current is accessed outside allowed contexts (e.g., effects or event handlers).Sources:
Calling setState unconditionally during render causes infinite update loops (render → setState → render indefinitely).
Implementation highlights of validateNoSetStateInRender:
computeUnconditionalBlocks.setState.setState is found called in unconditional paths or inside useMemo callbacks, it reports an error.setState.useKeyedState.Sources:
React encourages computing derived values during render rather than within side-effect hooks like useEffect.
validateNoDerivedComputationsInEffects_exp flags effects that perform state updates with values fully derived from props or state, which suggests the effect is unnecessary.
Implementation details:
DerivationCache to compute data-flow and derivation relationships between variables.fromProps, fromState, etc.).Sources:
The compiler sometimes auto-infers memoization dependencies and removes manual memoization. However, when developers explicitly memoize computations with useMemo or useCallback, the compiler validates that these memoizations are preserved in the output.
Pass details for validatePreservedManualMemoization:
ReactiveFunction with a visitor tracking manual memo blocks.let variable reassignments arising from memoization function inlining.DropManualMemoization.ref.current access.Sources:
React components are capitalized and should be invoked via JSX syntax, not as plain function calls. The validateNoCapitalizedCalls pass detects attempts to call capitalized functions directly.
Key points:
LoadGlobal and PropertyLoad instructions with capitalized names.CallExpression or MethodCall using these capitalized identifiers.Sources:
CompilerError is the central class for validation error aggregation. It is designed to:
CompilerDiagnostic entries with unique categories and severity.Environment to forward diagnostics to Babel plugin error reporting.RenderSetState).SourceLocation) where error arises.Sources:
| Pass Name | Description | Input Level | Key Concepts / Functions |
|---|---|---|---|
validateExhaustiveDependencies | Validates exhaustive and exact deps for useMemo, useEffect | HIR | collectDependencies, validateDependencies |
validateNoRefAccessInRender | Ensures no ref.current access during render | HIR | RefAccessType, dataflow Env |
validateNoSetStateInRender | Detects unsafe unconditional setState calls during render | HIR | computeUnconditionalBlocks |
validateNoDerivedComputationsInEffects_exp | Ensures derived computations happen in render, not effects | HIR | DerivationCache, fixpoint iteration |
validatePreservedManualMemoization | Validates memoization is preserved after transformations | ReactiveFunction | compareDeps, visitor pattern |
validateNoCapitalizedCalls | Prevents improper invocation of capitalized functions (components) | HIR | Identifier name checks |
Sources:
This detailed documentation provides insights into the React Compiler's validation passes, their implementation, and how errors propagate through the compiler’s environment, ensuring robust and React-compliant output code.
Sources:
Refresh this wiki