The React Compiler doesn't handle all of JavaScript yet. When it finds something it can't handle in a component or hook, it skips that function. The code is valid and still works, but it gets no automatic memoization. Turn this rule on to find those components.
Some of what it reports:
trywithfinally, andthrowinsidetryvar??=,||=and&&=count++on a variable that a nested function also usesthis, class expressions, and getters in object literals- BigInt literals, tagged templates with
${}, dynamicimport() for await, andfor (;;)without a condition
Configure
Off by default. To turn it on:
bunfig.toml
[lint.rules]
"react-hooks/todo" = "error" # or "warn"
Examples
Reported:
function Report({ load }) {
let rows = [];
try {
rows = load();
} finally {
log("loaded");
}
return <Table rows={rows} />;
}
function Report(props) {
let rows = props.rows;
rows ??= [];
return <Table rows={rows} />;
}
function Report({ rows }) {
let clicks = 0;
const onClick = () => {
clicks++;
};
return <Table rows={rows} onClick={onClick} />;
}
Not reported:
function Report({ load }) {
let rows = [];
try {
rows = load();
} catch (error) {
rows = [];
}
log("loaded");
return <Table rows={rows} />;
}
function Report(props) {
const rows = props.rows ?? [];
return <Table rows={rows} />;
}
A function that's neither a component nor a hook is never compiled, so it can use anything:
function loadRows(load) {
try {
return load();
} finally {
log("loaded");
}
}
When not to use it
If you don't use the React Compiler, there's nothing to fix here. Even if you do, rewriting working code is only worth it for components that are slow to render.