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`.
This commit is contained in:
Joe Savona
2023-04-04 12:30:11 -07:00
parent 2e3aa3954c
commit 939582dae0
2 changed files with 83 additions and 0 deletions
@@ -0,0 +1,62 @@
## Input
```javascript
function Component(props) {
const item = useMutable(props.itemId);
const dispatch = useDispatch();
const exit = useCallback(() => {
dispatch(createExitAction());
}, [dispatch]);
useEffect(() => {
const cleanup = GlobalEventEmitter.addListener("onInput", () => {
if (item.value) {
exit();
}
});
return () => cleanup.remove();
}, [exit, item]);
maybeMutate(item);
return <div />;
}
```
## Code
```javascript
function Component(props) {
const $ = React.unstable_useMemoCache(1);
const item = useMutable(props.itemId);
const dispatch = useDispatch();
const exit = () => {
dispatch(createExitAction());
};
useEffect(() => {
const cleanup = GlobalEventEmitter.addListener("onInput", () => {
if (item.value) {
exit();
}
});
return () => cleanup.remove();
}, [exit, item]);
maybeMutate(item);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = <div />;
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
```
@@ -0,0 +1,21 @@
function Component(props) {
const item = useMutable(props.itemId);
const dispatch = useDispatch();
const exit = useCallback(() => {
dispatch(createExitAction());
}, [dispatch]);
useEffect(() => {
const cleanup = GlobalEventEmitter.addListener("onInput", () => {
if (item.value) {
exit();
}
});
return () => cleanup.remove();
}, [exit, item]);
maybeMutate(item);
return <div />;
}