You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Alternative to facebook#34276
---
(Summary taken from @josephsavona 's facebook#34276)
Partial fix for facebook#34262. Consider this example:
```js
function useInputValue(input) {
const object = React.useMemo(() => {
const {value} = transform(input);
return {value};
}, [input]);
return object;
}
```
React Compiler breaks this code into two reactive scopes:
* One for `transform(input)`
* One for `{value}`
When we run ValidatePreserveExistingMemo, we see that the scope for
`{value}` has the dependency `value`, whereas the original memoization
had the dependency `input`, and throw an error that the dependencies
didn't match.
In other words, we're flagging the fact that memoized _better than the
user_ as a problem. The more complete solution would be to validate that
there is a subgraph of reactive scopes with a single input and output
node, where the input node has the same dependencies as the original
useMemo, and the output has the same outputs. That is true in this case,
with the subgraph being the two consecutive scopes mentioned above.
But that's complicated. As a shortcut, this PR checks for any
dependencies that are defined after the start of the original useMemo.
If we find one, we know that it's a case where we were able to memoize
more precisely than the original, and we don't report an error on the
dependency. We still check that the original _output_ value is able to
be memoized, though. So if the scope of `object` were extended, eg with
a call to `mutate(object)`, then we'd still correctly report an error
that we couldn't preserve memoization.
Co-authored-by: Joe Savona <joesavona@fb.com>
* Repro from https://github.com/facebook/react/issues/34262
9
+
*
10
+
* The compiler memoizes more precisely than the original code, with two reactive scopes:
11
+
* - One for `transform(input)` with `input` as dep
12
+
* - One for `{value}` with `value` as dep
13
+
*
14
+
* When we validate preserving manual memoization we incorrectly reject this, because
15
+
* the original memoization had `object` depending on `input` but our scope depends on
16
+
* `value`.
17
+
*
18
+
* This fixture adds a later potential mutation, which extends the scope and should
19
+
* fail validation. This confirms that even though we allow the dependency to diverge,
20
+
* we still check that the output value is memoized.
21
+
*/
22
+
functionuseInputValue(input) {
23
+
constobject=React.useMemo(() => {
24
+
const {value} =transform(input);
25
+
return {value};
26
+
}, [input]);
27
+
mutate(object);
28
+
return object;
29
+
}
30
+
31
+
```
32
+
33
+
34
+
## Error
35
+
36
+
```
37
+
Found 1 error:
38
+
39
+
Compilation Skipped: Existing memoization could not be preserved
40
+
41
+
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.
Compilation Skipped: Existing memoization could not be preserved
51
+
52
+
React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly.
0 commit comments