-
Notifications
You must be signed in to change notification settings - 8000 Fork 48.4k
[Compiler]: skipped memoization due to potential modification after hook call #33050
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Thanks for posting. What's happening here is that the compiler sees a value being constructed and (potentially) modified later: const data = { value }; // <-- value created here
// ...
prop2: doSomething({ data }) // <-- value possibly modified here React Compiler doesn't know what React Compiler always groups modification of values together w the code that creates the value (otherwise we might repeatedly mutate the same value, which is bad). But that doesn't work in this case, because there is also a hook call! cosnt data = { value };
...
useSomething({ data });
...
doSomething({ data }); To memoize We're constantly working to improve our heuristics for edge cases like this, but there are some cases where we have to skip memoization out of an abundance of caution. |
Thanks for the explanation. It actually makes sense to skip memoization in this case, though it technically breaks the React rule of keeping renders pure, since But I did notice that if the regular function call comes before the hook, memoization is still generated: const useCustomHook = (value) => {
const data = { value };
return {
// swap the order of the regular function call and hook
prop1: doSomething({ data }),
prop2: useSomething({ data }),
};
}; Compiled output: let data;
let t0;
if ($[0] !== value) {
data = { value };
t0 = doSomething({ data });
$[0] = value;
$[1] = data;
$[2] = t0;
} else {
data = $[1];
t0 = $[2];
}
let t1;
if ($[3] !== data) {
t1 = { data };
$[3] = data;
$[4] = t1;
} else {
t1 = $[4];
}
const t2 = useSomething(t1); It seems the assumption here is that if However, memoization might break the code. For example, if So if there's a chance that hook arguments are modified by a regular function, it's probably safer to skip memoization consistently, regardless of the order of the hook and the function call. |
What kind of issue is this?
Link to repro
https://playground.react.dev/#N4Igzg9grgTgxgUxALhASwLYAcIwC4AEwBUYCAyhBgngBZoB2A5gDQEAmEl1djTBAXwIAzGFQIBySNQC0AGzQAjCQG4AOgw1wIDMIVIIAwqTxUAEhAgBrAgF4CACgBuAQzlQEASjsA+IhoICbV1Cdhc8FzsiAld3BEF1TQZAmBpYZOAAwIIsMSwARmQSMm4aemYHYjCIwU8WLMDciCwAJiLOUt4KqvDIgU8sgUShjQ0EAA8cfGiDYz1zSxsRhhABIA
Repro steps
Currently, the compiler memoizes the arguments of React hooks and regular functions when the arguments are non-primitive values. However, the behavior is inconsistent, and memoization is skipped when certain conditions are met:
Here is a minimal example:
In the example, memoization of the
{ data }
argument passed to bothuseSomething
anddoSomething
is skipped.How often does this bug happen?
Every time
What version of React are you using?
19.1.0
What version of React Compiler are you using?
19.1.0-rc.1
The text was updated successfully, but these errors were encountered: