@samitouri / QOS-React-2 / commits / 939582dae0

Repro for unmemoized readonly callback

Repro of a closure that we currently treat as readonly because it captures a possibly-mutable value, but which we later realize is not mutable. Specifically, when we check `exit()` we think `dispatch()` is mutable and therefore consider it captured, which means we can't independently memoize `exit`.

Joe Savona committed Apr 4, 2023 at 12:30 UTC 939582dae02fc70c6b86f82492427249d0b3e1df
2 files changed +83
compiler/forget/src/__tests__/fixtures/compiler/useEffect-nested-lambdas.expect.md new
+62
@@ -0,0 +1,62 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function Component(props) {
6 + const item = useMutable(props.itemId);
7 + const dispatch = useDispatch();
8 +
9 + const exit = useCallback(() => {
10 + dispatch(createExitAction());
11 + }, [dispatch]);
12 +
13 + useEffect(() => {
14 + const cleanup = GlobalEventEmitter.addListener("onInput", () => {
15 + if (item.value) {
16 + exit();
17 + }
18 + });
19 + return () => cleanup.remove();
20 + }, [exit, item]);
21 +
22 + maybeMutate(item);
23 +
24 + return <div />;
25 +}
26 +
27 +```
28 +
29 +## Code
30 +
31 +```javascript
32 +function Component(props) {
33 + const $ = React.unstable_useMemoCache(1);
34 + const item = useMutable(props.itemId);
35 + const dispatch = useDispatch();
36 +
37 + const exit = () => {
38 + dispatch(createExitAction());
39 + };
40 +
41 + useEffect(() => {
42 + const cleanup = GlobalEventEmitter.addListener("onInput", () => {
43 + if (item.value) {
44 + exit();
45 + }
46 + });
47 + return () => cleanup.remove();
48 + }, [exit, item]);
49 +
50 + maybeMutate(item);
51 + let t0;
52 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
53 + t0 = <div />;
54 + $[0] = t0;
55 + } else {
56 + t0 = $[0];
57 + }
58 + return t0;
59 +}
60 +
61 +```
62 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/compiler/useEffect-nested-lambdas.js new
+21
@@ -0,0 +1,21 @@
1 +function Component(props) {
2 + const item = useMutable(props.itemId);
3 + const dispatch = useDispatch();
4 +
5 + const exit = useCallback(() => {
6 + dispatch(createExitAction());
7 + }, [dispatch]);
8 +
9 + useEffect(() => {
10 + const cleanup = GlobalEventEmitter.addListener("onInput", () => {
11 + if (item.value) {
12 + exit();
13 + }
14 + });
15 + return () => cleanup.remove();
16 + }, [exit, item]);
17 +
18 + maybeMutate(item);
19 +
20 + return <div />;
21 +}