1
+
2
+## Input
3
+
4
+```javascript
5
+// @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
6
+import { useMemo, useState } from "react";
7
+import { Stringify, identity } from "shared-runtime";
8
+
9
+function Component({ value }) {
10
+ "use no forget";
11
+ const result = useValue(value);
12
+ return <Validate inputs={[value]} output={result} />;
13
+}
14
+
15
+function Validate({ inputs, output }) {
16
+ "use no forget";
17
+ const [previousInputs, setPreviousInputs] = useState(inputs);
18
+ const [previousOutput, setPreviousOutput] = useState(output);
19
+ if (
20
+ inputs.length !== previousInputs.length ||
21
+ inputs.some((item, i) => item !== previousInputs[i])
22
+ ) {
23
+ // Some input changed, we expect the output to change
24
+ setPreviousInputs(inputs);
25
+ setPreviousOutput(output);
26
+ } else if (output !== previousOutput) {
27
+ // Else output should be stable
28
+ throw new Error("Output identity changed but inputs did not");
29
+ }
30
+ return <Stringify inputs={inputs} output={output} />;
31
+}
32
+
33
+function useValue(value) {
34
+ return useMemo(() => {
35
+ if (value == null) {
36
+ return null;
37
+ }
38
+ try {
39
+ return { value };
40
+ } catch (e) {
41
+ return null;
42
+ }
43
+ }, [value]);
44
+}
45
+
46
+export const FIXTURE_ENTRYPOINT = {
47
+ fn: Component,
48
+ params: [{ value: null }],
49
+ sequentialRenders: [
50
+ { value: null },
51
+ { value: null },
52
+ { value: 42 },
53
+ { value: 42 },
54
+ { value: null },
55
+ { value: 42 },
56
+ { value: null },
57
+ { value: 42 },
58
+ ],
59
+};
60
+
61
+```
62
+
63
+## Code
64
+
65
+```javascript
66
+// @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
67
+import {
68
+ useMemo,
69
+ useState,
70
+ unstable_useMemoCache as useMemoCache,
71
+} from "react";
72
+import { Stringify, identity } from "shared-runtime";
73
+
74
+function Component({ value }) {
75
+ "use no forget";
76
+ const result = useValue(value);
77
+ return <Validate inputs={[value]} output={result} />;
78
+}
79
+
80
+function Validate({ inputs, output }) {
81
+ "use no forget";
82
+ const [previousInputs, setPreviousInputs] = useState(inputs);
83
+ const [previousOutput, setPreviousOutput] = useState(output);
84
+ if (
85
+ inputs.length !== previousInputs.length ||
86
+ inputs.some((item, i) => item !== previousInputs[i])
87
+ ) {
88
+ // Some input changed, we expect the output to change
89
+ setPreviousInputs(inputs);
90
+ setPreviousOutput(output);
91
+ } else if (output !== previousOutput) {
92
+ // Else output should be stable
93
+ throw new Error("Output identity changed but inputs did not");
94
+ }
95
+ return <Stringify inputs={inputs} output={output} />;
96
+}
97
+
98
+function useValue(value) {
99
+ const $ = useMemoCache(5);
100
+ let t0;
101
+ bb13: {
102
+ if (value == null) {
103
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
104
+ t0 = null;
105
+ break bb13;
106
+ $[0] = t0;
107
+ } else {
108
+ t0 = $[0];
109
+ }
110
+ }
111
+ try {
112
+ let t2;
113
+ if ($[1] !== value) {
114
+ t2 = { value };
115
+ $[1] = value;
116
+ $[2] = t2;
117
+ } else {
118
+ t2 = $[2];
119
+ }
120
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
121
+ t0 = t2;
122
+ $[3] = t0;
123
+ } else {
124
+ t0 = $[3];
125
+ }
126
+ } catch (t1) {
127
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
128
+ t0 = null;
129
+ $[4] = t0;
130
+ } else {
131
+ t0 = $[4];
132
+ }
133
+ }
134
+ }
135
+ return t0;
136
+}
137
+
138
+export const FIXTURE_ENTRYPOINT = {
139
+ fn: Component,
140
+ params: [{ value: null }],
141
+ sequentialRenders: [
142
+ { value: null },
143
+ { value: null },
144
+ { value: 42 },
145
+ { value: 42 },
146
+ { value: null },
147
+ { value: 42 },
148
+ { value: null },
149
+ { value: 42 },
150
+ ],
151
+};
152
+
153
+```
154
+
155
+### Eval output
156
+(kind: ok) <div>{"inputs":[null],"output":"[[ cyclic ref *2 ]]"}</div>
157
+<div>{"inputs":[null],"output":"[[ cyclic ref *2 ]]"}</div>
158
+<div>{"inputs":[42],"output":{"value":42}}</div>
159
+<div>{"inputs":[42],"output":{"value":42}}</div>
160
+<div>{"inputs":[null],"output":"[[ cyclic ref *2 ]]"}</div>
161
+<div>{"inputs":[42],"output":{"value":42}}</div>
162
+<div>{"inputs":[null],"output":"[[ cyclic ref *2 ]]"}</div>
163
+<div>{"inputs":[42],"output":{"value":42}}</div>
\ No newline at end of file