Validation & Error Handling
The React Compiler includes a validation engine designed to enforce React's rules and ensure that your components remain predictable and efficient. Unlike standard linters, the compiler performs deep semantic analysis of your code to detect patterns that might break React’s lifecycle or lead to suboptimal performance.
Capitalized Call Restrictions
React reserves capitalized function names for Components. Components must be rendered using JSX (e.g., <MyComponent />) rather than being invoked as standard JavaScript functions (e.g., MyComponent()).
Calling a component as a function bypasses React's internal reconciliation process, which can lead to bugs with hooks and state management.
Examples of Invalid Calls
The compiler will trigger an error if it detects capitalized functions being called directly:
function Foo() {
// ❌ Error: Capitalized functions are reserved for components
const x = SomeComponent();
// ❌ Error: Capitalized methods are also restricted
const y = globalNamespace.MyHelper();
return <div>{x}</div>;
}
Configuration and Allowlisting
If you have external libraries or global utilities that use capitalized names but are not React components (such as Boolean(), Number(), or String()), you can configure the compiler to ignore them via the validateNoCapitalizedCalls allowlist.
Common globals like Boolean, Number, and String are allowlisted by default.
Hook Patterns and Naming
The compiler relies on the use prefix to identify Hooks. This naming convention is critical for the compiler to determine which values "escape" the current scope and must be memoized.
Custom Hook Patterns
By default, the compiler matches the standard use[A-Z] pattern. You can customize this behavior in your compiler configuration using a regex:
{
"hookPattern": ".*\\b(use[^$]+)$"
}
This ensures that internal aliasing (e.g., const React$useState = React.useState) is correctly identified as a hook call and does not trigger "capitalized call" errors.
Memoization & Escape Analysis
The compiler uses "Escape Analysis" to determine which variables need to be wrapped in reactive scopes. A value is considered to "escape" if:
- It is returned by a function.
- It is passed as an argument to a Hook (since the Hook might store a reference to it).
Validation of Existing Memoization
If you are migrating a codebase that already uses manual memoization (useMemo, useCallback), you can enable strict validation to ensure the compiler honors your existing performance guarantees.
Using the @validatePreserveExistingMemoizationGuarantees pragma, the compiler will verify that its automated pruning does not break the stability of values you previously chose to memoize manually.
// @validatePreserveExistingMemoizationGuarantees
import { useMemo } from 'react';
function ProductList({ items }) {
// The compiler ensures this block remains stable
// and doesn't invalidate more often than the original code.
const processed = useMemo(() => {
return items.map(transform);
}, [items]);
return <List data={processed} />;
}
Error Categories
When the compiler encounters code that violates React's rules, it produces a CompilerError. These errors generally fall into the following categories:
| Category | Description |
| :--- | :--- |
| CapitalizedCalls | Attempting to call a potential component as a standard function. |
| InvalidReact | General violations of React rules (e.g., calling hooks inside loops). |
| PreserveMemo | Failure to maintain the stability of an existing useMemo or useCallback boundary. |
Troubleshooting Errors
Each error includes:
- Reason: A high-level explanation of the rule being enforced.
- Description: Specific details about the offending identifier or expression.
- Location: The exact file line and column where the violation occurred.
If the compiler flags a valid piece of code, you can use the @expectNothingCompiled pragma to opt-out specific functions from compilation while you address the underlying structure.