@reckona/mreact-compat 0.0.91 → 0.0.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/class-component.d.ts +20 -6
- package/dist/class-component.d.ts.map +1 -1
- package/dist/class-component.js +94 -51
- package/dist/class-component.js.map +1 -1
- package/dist/context.d.ts +19 -3
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +55 -6
- package/dist/context.js.map +1 -1
- package/dist/dom-children.d.ts +2 -0
- package/dist/dom-children.d.ts.map +1 -1
- package/dist/dom-children.js +103 -1
- package/dist/dom-children.js.map +1 -1
- package/dist/dom-host-rules.d.ts +10 -0
- package/dist/dom-host-rules.d.ts.map +1 -0
- package/dist/dom-host-rules.js +86 -0
- package/dist/dom-host-rules.js.map +1 -0
- package/dist/dom-props.d.ts +3 -2
- package/dist/dom-props.d.ts.map +1 -1
- package/dist/dom-props.js +229 -33
- package/dist/dom-props.js.map +1 -1
- package/dist/element.d.ts +9 -4
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +101 -26
- package/dist/element.js.map +1 -1
- package/dist/event-listeners.d.ts +4 -4
- package/dist/event-listeners.d.ts.map +1 -1
- package/dist/event-listeners.js +1 -1
- package/dist/event-listeners.js.map +1 -1
- package/dist/event-types.d.ts +10 -0
- package/dist/event-types.d.ts.map +1 -1
- package/dist/event-types.js.map +1 -1
- package/dist/events.js +22 -1
- package/dist/events.js.map +1 -1
- package/dist/fiber-commit.d.ts +2 -1
- package/dist/fiber-commit.d.ts.map +1 -1
- package/dist/fiber-commit.js +13 -1
- package/dist/fiber-commit.js.map +1 -1
- package/dist/fiber-reconciler.d.ts.map +1 -1
- package/dist/fiber-reconciler.js +28 -7
- package/dist/fiber-reconciler.js.map +1 -1
- package/dist/fiber-work-loop.d.ts.map +1 -1
- package/dist/fiber-work-loop.js +4 -3
- package/dist/fiber-work-loop.js.map +1 -1
- package/dist/fiber.d.ts +5 -0
- package/dist/fiber.d.ts.map +1 -1
- package/dist/fiber.js +9 -0
- package/dist/fiber.js.map +1 -1
- package/dist/hooks-entry.d.ts +3 -0
- package/dist/hooks-entry.d.ts.map +1 -0
- package/dist/hooks-entry.js +2 -0
- package/dist/hooks-entry.js.map +1 -0
- package/dist/hooks.d.ts +39 -5
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +373 -326
- package/dist/hooks.js.map +1 -1
- package/dist/host-reconciler.d.ts +3 -0
- package/dist/host-reconciler.d.ts.map +1 -1
- package/dist/host-reconciler.js +1152 -64
- package/dist/host-reconciler.js.map +1 -1
- package/dist/hydration.d.ts +1 -1
- package/dist/hydration.d.ts.map +1 -1
- package/dist/hydration.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/react-default.d.ts +4 -4
- package/dist/react-default.d.ts.map +1 -1
- package/dist/react-default.js +2 -1
- package/dist/react-default.js.map +1 -1
- package/dist/reconciler.d.ts.map +1 -1
- package/dist/reconciler.js +38 -22
- package/dist/reconciler.js.map +1 -1
- package/dist/root.d.ts.map +1 -1
- package/dist/root.js +48 -13
- package/dist/root.js.map +1 -1
- package/dist/server-render.d.ts +6 -0
- package/dist/server-render.d.ts.map +1 -0
- package/dist/server-render.js +307 -0
- package/dist/server-render.js.map +1 -0
- package/package.json +6 -2
- package/src/class-component.ts +216 -51
- package/src/context.ts +108 -9
- package/src/dom-children.ts +155 -1
- package/src/dom-host-rules.ts +115 -0
- package/src/dom-props.ts +297 -46
- package/src/element.ts +141 -31
- package/src/event-listeners.ts +6 -6
- package/src/event-types.ts +10 -0
- package/src/events.ts +32 -10
- package/src/fiber-commit.ts +16 -1
- package/src/fiber-reconciler.ts +39 -6
- package/src/fiber-work-loop.ts +4 -3
- package/src/fiber.ts +14 -0
- package/src/hooks-entry.ts +24 -0
- package/src/hooks.ts +482 -479
- package/src/host-reconciler.ts +1628 -94
- package/src/hydration.ts +1 -1
- package/src/index.ts +1 -1
- package/src/react-default.ts +1 -1
- package/src/reconciler.ts +61 -22
- package/src/root.ts +55 -12
- package/src/server-render.ts +478 -0
package/src/hooks.ts
CHANGED
|
@@ -1,26 +1,13 @@
|
|
|
1
1
|
import { scheduleCallback } from "./fiber-scheduler.js";
|
|
2
|
+
import { removeChildIfPresent } from "./dom-children.js";
|
|
2
3
|
import {
|
|
3
|
-
|
|
4
|
-
Fragment,
|
|
5
|
-
FORWARD_REF_TYPE,
|
|
6
|
-
MEMO_TYPE,
|
|
7
|
-
Profiler,
|
|
8
|
-
isReactCompatElement,
|
|
9
|
-
type ForwardRefType,
|
|
10
|
-
type MemoType,
|
|
11
|
-
type ReactCompatElement,
|
|
12
|
-
type ReactCompatNode,
|
|
13
|
-
} from "./element.js";
|
|
14
|
-
import {
|
|
4
|
+
type ReactCompatContextLike,
|
|
15
5
|
isReactCompatContext,
|
|
16
|
-
|
|
17
|
-
isReactCompatProvider,
|
|
18
|
-
renderWithContextProvider,
|
|
6
|
+
readContextValue,
|
|
19
7
|
useContext,
|
|
8
|
+
withContextReadObserver,
|
|
20
9
|
} from "./context.js";
|
|
21
10
|
import { isThenable } from "./thenable.js";
|
|
22
|
-
import { isDangerousHtmlAttribute, isDangerousHtmlOptIn } from "./url-safety.js";
|
|
23
|
-
import { escapeHtmlAttribute as escapeHtml } from "@reckona/mreact-shared/html-escape";
|
|
24
11
|
|
|
25
12
|
export interface RootRuntime {
|
|
26
13
|
currentElement?: unknown;
|
|
@@ -35,11 +22,19 @@ export interface RootRuntime {
|
|
|
35
22
|
pendingEffects: PendingEffect[];
|
|
36
23
|
externalStoreChecks: ExternalStoreCheck[];
|
|
37
24
|
portalContainers: Set<Element>;
|
|
25
|
+
portalNodes: Map<Element, Set<Node>>;
|
|
38
26
|
idCounter: number;
|
|
39
27
|
identifierPrefix: string;
|
|
40
28
|
idMode: "client" | "server";
|
|
41
29
|
strictModeDepth: number;
|
|
30
|
+
strictReplayDepth: number;
|
|
31
|
+
strictMemoCapture: unknown[] | undefined;
|
|
32
|
+
strictMemoCaptureByHook: Map<string, unknown> | undefined;
|
|
33
|
+
strictMemoReplay: { values: readonly unknown[]; index: number } | undefined;
|
|
34
|
+
strictMemoReplayByHook: ReadonlyMap<string, unknown> | undefined;
|
|
42
35
|
profilerFlushDepth: number;
|
|
36
|
+
effectFlushPhase: "insertion" | "layout" | "normal" | undefined;
|
|
37
|
+
externalStoreUpdate: boolean;
|
|
43
38
|
rerender(priority?: RenderPriority): void;
|
|
44
39
|
beginRender(): void;
|
|
45
40
|
endRender(committed?: boolean): void;
|
|
@@ -48,9 +43,13 @@ export interface RootRuntime {
|
|
|
48
43
|
}
|
|
49
44
|
|
|
50
45
|
interface ComponentInstance {
|
|
46
|
+
owner: unknown | undefined;
|
|
47
|
+
path: string;
|
|
51
48
|
hooks: HookSlot[];
|
|
52
49
|
hookIndex: number;
|
|
53
50
|
dirty: boolean;
|
|
51
|
+
disposed?: boolean;
|
|
52
|
+
contextDependencies?: Map<ReactCompatContextLike<unknown>, unknown>;
|
|
54
53
|
devToolsHooks: DevToolsHookValue[];
|
|
55
54
|
devToolsHookTypes: string[];
|
|
56
55
|
devToolsHookSuppressionDepth: number;
|
|
@@ -119,7 +118,7 @@ export type DevToolsHookValue =
|
|
|
119
118
|
| { kind: "effect"; effectKind: "insertion" | "layout" | "normal"; deps?: readonly unknown[] };
|
|
120
119
|
|
|
121
120
|
type HookSlot =
|
|
122
|
-
| { kind: "state"; value: unknown }
|
|
121
|
+
| { kind: "state"; value: unknown; hostCommitValue?: unknown }
|
|
123
122
|
| {
|
|
124
123
|
kind: "action-state";
|
|
125
124
|
state: unknown;
|
|
@@ -135,7 +134,7 @@ type HookSlot =
|
|
|
135
134
|
update: (state: unknown, payload: unknown) => unknown;
|
|
136
135
|
dispatch?: (payload: unknown) => void;
|
|
137
136
|
}
|
|
138
|
-
| { kind: "store"; value: unknown }
|
|
137
|
+
| { kind: "store"; value: unknown; hasMounted?: boolean }
|
|
139
138
|
| { kind: "ref"; value: { current: unknown } }
|
|
140
139
|
| { kind: "memo"; value: unknown; deps?: readonly unknown[] }
|
|
141
140
|
| { kind: "debug"; value: unknown }
|
|
@@ -146,12 +145,31 @@ type HookSlot =
|
|
|
146
145
|
deps?: readonly unknown[];
|
|
147
146
|
cleanup?: () => void;
|
|
148
147
|
disposed?: boolean;
|
|
148
|
+
mounted?: boolean;
|
|
149
149
|
strictReplay?: boolean;
|
|
150
150
|
};
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
interface HookRenderState {
|
|
153
|
+
currentRuntime: RootRuntime | undefined;
|
|
154
|
+
currentInstance: ComponentInstance | undefined;
|
|
155
|
+
currentCacheScope: CacheScope | undefined;
|
|
156
|
+
hostCommitDepth: number;
|
|
157
|
+
queuedHostCommitRerenders: Set<RootRuntime>;
|
|
158
|
+
queuedEffectFlushRerenders: Set<RootRuntime>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const HOOK_RENDER_STATE_KEY = Symbol.for("modular.react.hook_render_state");
|
|
162
|
+
const hookRenderState =
|
|
163
|
+
((globalThis as typeof globalThis & Record<symbol, HookRenderState | undefined>)[
|
|
164
|
+
HOOK_RENDER_STATE_KEY
|
|
165
|
+
] ??= {
|
|
166
|
+
currentRuntime: undefined,
|
|
167
|
+
currentInstance: undefined,
|
|
168
|
+
currentCacheScope: undefined,
|
|
169
|
+
hostCommitDepth: 0,
|
|
170
|
+
queuedHostCommitRerenders: new Set<RootRuntime>(),
|
|
171
|
+
queuedEffectFlushRerenders: new Set<RootRuntime>(),
|
|
172
|
+
});
|
|
155
173
|
const CACHE_SCOPE_SYMBOL = Symbol.for("modular.react.cache_scope");
|
|
156
174
|
const emptyCacheOwnerStack: string[] = [];
|
|
157
175
|
let syncVersion = 0;
|
|
@@ -162,18 +180,77 @@ let transitionRerenderScheduled = false;
|
|
|
162
180
|
let eventBatchDepth = 0;
|
|
163
181
|
let currentEventPriority: EventPriority = "default";
|
|
164
182
|
let eventRerenderScheduled = false;
|
|
183
|
+
let effectFlushRerenderDepth = 0;
|
|
184
|
+
let strictMemoOwnerId = 0;
|
|
185
|
+
const strictMemoObjectOwnerIds = new WeakMap<object, number>();
|
|
186
|
+
const strictMemoPrimitiveOwnerIds = new Map<unknown, number>();
|
|
165
187
|
const queuedTransitionRerenders = new Map<RootRuntime, TransitionContext>();
|
|
166
188
|
const queuedEventRerenders = new Set<RootRuntime>();
|
|
167
189
|
export const version = "19.2.6";
|
|
168
190
|
|
|
169
191
|
export function act<T>(callback: () => T): T extends PromiseLike<unknown> ? Promise<void> : void {
|
|
170
|
-
const
|
|
192
|
+
const previousPriority = currentEventPriority;
|
|
193
|
+
currentEventPriority = "discrete";
|
|
194
|
+
eventBatchDepth += 1;
|
|
195
|
+
let result: T;
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
result = callback();
|
|
199
|
+
} catch (error) {
|
|
200
|
+
eventBatchDepth -= 1;
|
|
201
|
+
currentEventPriority = previousPriority;
|
|
202
|
+
if (eventBatchDepth === 0) {
|
|
203
|
+
flushEventRerendersForPriority("discrete");
|
|
204
|
+
}
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const finishActScope = (): void => {
|
|
209
|
+
eventBatchDepth -= 1;
|
|
210
|
+
currentEventPriority = previousPriority;
|
|
211
|
+
if (eventBatchDepth === 0) {
|
|
212
|
+
flushEventRerendersForPriority("discrete");
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
if (isThenable(result)) {
|
|
217
|
+
return Promise.resolve(result).then(
|
|
218
|
+
async () => {
|
|
219
|
+
finishActScope();
|
|
220
|
+
await flushActWorkAsync();
|
|
221
|
+
},
|
|
222
|
+
(error: unknown) => {
|
|
223
|
+
finishActScope();
|
|
224
|
+
throw error;
|
|
225
|
+
},
|
|
226
|
+
) as T extends PromiseLike<unknown> ? Promise<void> : void;
|
|
227
|
+
}
|
|
171
228
|
|
|
172
|
-
|
|
229
|
+
finishActScope();
|
|
230
|
+
flushActWork();
|
|
231
|
+
return undefined as T extends PromiseLike<unknown>
|
|
173
232
|
? Promise<void>
|
|
174
233
|
: void;
|
|
175
234
|
}
|
|
176
235
|
|
|
236
|
+
async function flushActWorkAsync(): Promise<void> {
|
|
237
|
+
for (let attempt = 0; attempt < 10; attempt += 1) {
|
|
238
|
+
await Promise.resolve();
|
|
239
|
+
flushActWork();
|
|
240
|
+
}
|
|
241
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
242
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
243
|
+
flushActWork();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function flushActWork(): void {
|
|
248
|
+
flushQueuedEventRerenders("sync");
|
|
249
|
+
flushQueuedTransitionRerenders();
|
|
250
|
+
flushHostCommitRerenders();
|
|
251
|
+
flushEffectFlushRerenders();
|
|
252
|
+
}
|
|
253
|
+
|
|
177
254
|
export type EventPriority = "discrete" | "continuous" | "default";
|
|
178
255
|
export type RenderPriority = "sync" | "transition" | "continuous";
|
|
179
256
|
|
|
@@ -190,6 +267,7 @@ export interface RootRuntimeOptions {
|
|
|
190
267
|
export interface RuntimeSnapshot {
|
|
191
268
|
instanceKeys: Set<string>;
|
|
192
269
|
portalContainers: Set<Element>;
|
|
270
|
+
portalNodes: Map<Element, Set<Node>>;
|
|
193
271
|
pendingInsertionEffectsLength: number;
|
|
194
272
|
pendingLayoutEffectsLength: number;
|
|
195
273
|
pendingEffectsLength: number;
|
|
@@ -199,6 +277,11 @@ export interface RuntimeSnapshot {
|
|
|
199
277
|
identifierPrefix: string;
|
|
200
278
|
idMode: "client" | "server";
|
|
201
279
|
strictModeDepth: number;
|
|
280
|
+
strictReplayDepth: number;
|
|
281
|
+
strictMemoCapture: unknown[] | undefined;
|
|
282
|
+
strictMemoCaptureByHook: Map<string, unknown> | undefined;
|
|
283
|
+
strictMemoReplay: { values: readonly unknown[]; index: number } | undefined;
|
|
284
|
+
strictMemoReplayByHook: ReadonlyMap<string, unknown> | undefined;
|
|
202
285
|
profilerFlushDepth: number;
|
|
203
286
|
}
|
|
204
287
|
|
|
@@ -218,11 +301,19 @@ export function createRootRuntime(
|
|
|
218
301
|
pendingEffects: [],
|
|
219
302
|
externalStoreChecks: [],
|
|
220
303
|
portalContainers: new Set(),
|
|
304
|
+
portalNodes: new Map(),
|
|
221
305
|
idCounter: 0,
|
|
222
306
|
identifierPrefix: options.identifierPrefix ?? "",
|
|
223
307
|
idMode: options.idMode ?? "client",
|
|
224
308
|
strictModeDepth: 0,
|
|
309
|
+
strictReplayDepth: 0,
|
|
310
|
+
strictMemoCapture: undefined,
|
|
311
|
+
strictMemoCaptureByHook: undefined,
|
|
312
|
+
strictMemoReplay: undefined,
|
|
313
|
+
strictMemoReplayByHook: undefined,
|
|
225
314
|
profilerFlushDepth: 0,
|
|
315
|
+
effectFlushPhase: undefined,
|
|
316
|
+
externalStoreUpdate: false,
|
|
226
317
|
rerender,
|
|
227
318
|
beginRender() {
|
|
228
319
|
this.activeInstanceKeys = new Set();
|
|
@@ -245,23 +336,33 @@ export function createRootRuntime(
|
|
|
245
336
|
}
|
|
246
337
|
this.activeInstanceKeys = undefined;
|
|
247
338
|
this.activeProfilerPaths = undefined;
|
|
248
|
-
currentRuntime = undefined;
|
|
249
|
-
currentInstance = undefined;
|
|
339
|
+
hookRenderState.currentRuntime = undefined;
|
|
340
|
+
hookRenderState.currentInstance = undefined;
|
|
250
341
|
if (committed) {
|
|
251
342
|
flushProfilerCommits(this, profilerCommits);
|
|
343
|
+
flushHostCommitRerenders();
|
|
344
|
+
this.externalStoreUpdate = false;
|
|
252
345
|
}
|
|
253
346
|
},
|
|
254
347
|
flushEffects() {
|
|
255
348
|
this.profilerFlushDepth += 1;
|
|
256
349
|
try {
|
|
350
|
+
this.effectFlushPhase = "insertion";
|
|
257
351
|
flushPendingEffects(this.pendingInsertionEffects);
|
|
352
|
+
this.effectFlushPhase = "layout";
|
|
258
353
|
const strictLayoutEffects = flushPendingEffects(this.pendingLayoutEffects);
|
|
354
|
+
this.effectFlushPhase = "normal";
|
|
259
355
|
const strictEffects = flushPendingEffects(this.pendingEffects);
|
|
356
|
+
this.effectFlushPhase = undefined;
|
|
260
357
|
const strictReplayEffects = [...strictLayoutEffects, ...strictEffects];
|
|
261
358
|
cleanupStrictEffects(strictReplayEffects);
|
|
262
359
|
replayStrictEffects(strictReplayEffects);
|
|
263
360
|
} finally {
|
|
361
|
+
this.effectFlushPhase = undefined;
|
|
264
362
|
this.profilerFlushDepth -= 1;
|
|
363
|
+
if (this.profilerFlushDepth === 0) {
|
|
364
|
+
flushEffectFlushRerenders();
|
|
365
|
+
}
|
|
265
366
|
}
|
|
266
367
|
},
|
|
267
368
|
dispose() {
|
|
@@ -276,10 +377,7 @@ export function createRootRuntime(
|
|
|
276
377
|
this.activeProfilerPaths = undefined;
|
|
277
378
|
this.mountedProfilerPaths.clear();
|
|
278
379
|
this.profilerBaseDurations.clear();
|
|
279
|
-
|
|
280
|
-
container.replaceChildren();
|
|
281
|
-
}
|
|
282
|
-
this.portalContainers.clear();
|
|
380
|
+
clearRuntimePortalNodes(this);
|
|
283
381
|
},
|
|
284
382
|
};
|
|
285
383
|
}
|
|
@@ -299,9 +397,9 @@ export function refreshCacheScope(scope: CacheScope): void {
|
|
|
299
397
|
}
|
|
300
398
|
|
|
301
399
|
export function runWithCacheScope<T>(scope: CacheScope, callback: () => T): T {
|
|
302
|
-
const previousScope = currentCacheScope;
|
|
400
|
+
const previousScope = hookRenderState.currentCacheScope;
|
|
303
401
|
const previousGlobalScope = getGlobalCacheScope();
|
|
304
|
-
currentCacheScope = scope;
|
|
402
|
+
hookRenderState.currentCacheScope = scope;
|
|
305
403
|
setGlobalCacheScope(scope);
|
|
306
404
|
|
|
307
405
|
try {
|
|
@@ -309,16 +407,16 @@ export function runWithCacheScope<T>(scope: CacheScope, callback: () => T): T {
|
|
|
309
407
|
|
|
310
408
|
if (isThenable(result)) {
|
|
311
409
|
return Promise.resolve(result).finally(() => {
|
|
312
|
-
currentCacheScope = previousScope;
|
|
410
|
+
hookRenderState.currentCacheScope = previousScope;
|
|
313
411
|
setGlobalCacheScope(previousGlobalScope);
|
|
314
412
|
}) as T;
|
|
315
413
|
}
|
|
316
414
|
|
|
317
|
-
currentCacheScope = previousScope;
|
|
415
|
+
hookRenderState.currentCacheScope = previousScope;
|
|
318
416
|
setGlobalCacheScope(previousGlobalScope);
|
|
319
417
|
return result;
|
|
320
418
|
} catch (error) {
|
|
321
|
-
currentCacheScope = previousScope;
|
|
419
|
+
hookRenderState.currentCacheScope = previousScope;
|
|
322
420
|
setGlobalCacheScope(previousGlobalScope);
|
|
323
421
|
throw error;
|
|
324
422
|
}
|
|
@@ -332,7 +430,7 @@ export function renderWithProfiler<T>(
|
|
|
332
430
|
): T {
|
|
333
431
|
const startTime = getCurrentTime();
|
|
334
432
|
const phase: ProfilerPhase =
|
|
335
|
-
runtime.profilerFlushDepth > 0
|
|
433
|
+
runtime.profilerFlushDepth > 0 || effectFlushRerenderDepth > 0
|
|
336
434
|
? "nested-update"
|
|
337
435
|
: runtime.mountedProfilerPaths.has(path)
|
|
338
436
|
? "update"
|
|
@@ -368,10 +466,20 @@ export function renderWithRootRuntime<T>(
|
|
|
368
466
|
runtime: RootRuntime,
|
|
369
467
|
path: string,
|
|
370
468
|
render: () => T,
|
|
469
|
+
owner?: unknown,
|
|
371
470
|
): T {
|
|
372
|
-
const previousRuntime = currentRuntime;
|
|
373
|
-
const previousInstance = currentInstance;
|
|
374
|
-
|
|
471
|
+
const previousRuntime = hookRenderState.currentRuntime;
|
|
472
|
+
const previousInstance = hookRenderState.currentInstance;
|
|
473
|
+
let instance = runtime.instances.get(path);
|
|
474
|
+
|
|
475
|
+
if (instance !== undefined && owner !== undefined && instance.owner !== owner) {
|
|
476
|
+
cleanupInstance(instance);
|
|
477
|
+
instance = undefined;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
instance ??= {
|
|
481
|
+
owner,
|
|
482
|
+
path,
|
|
375
483
|
hooks: [],
|
|
376
484
|
hookIndex: 0,
|
|
377
485
|
dirty: false,
|
|
@@ -379,22 +487,56 @@ export function renderWithRootRuntime<T>(
|
|
|
379
487
|
devToolsHookTypes: [],
|
|
380
488
|
devToolsHookSuppressionDepth: 0,
|
|
381
489
|
};
|
|
490
|
+
instance.owner = owner;
|
|
491
|
+
instance.path = path;
|
|
382
492
|
runtime.instances.set(path, instance);
|
|
383
493
|
runtime.activeInstanceKeys?.add(path);
|
|
384
494
|
instance.hookIndex = 0;
|
|
385
495
|
instance.dirty = false;
|
|
496
|
+
instance.disposed = false;
|
|
497
|
+
delete instance.contextDependencies;
|
|
386
498
|
instance.devToolsHooks = [];
|
|
387
499
|
instance.devToolsHookTypes = [];
|
|
388
500
|
instance.devToolsHookSuppressionDepth = 0;
|
|
389
|
-
currentRuntime = runtime;
|
|
390
|
-
currentInstance = instance;
|
|
501
|
+
hookRenderState.currentRuntime = runtime;
|
|
502
|
+
hookRenderState.currentInstance = instance;
|
|
391
503
|
|
|
392
504
|
try {
|
|
393
|
-
return
|
|
505
|
+
return withContextReadObserver((context, value) => {
|
|
506
|
+
(instance.contextDependencies ??= new Map()).set(context, value);
|
|
507
|
+
}, render);
|
|
394
508
|
} finally {
|
|
395
|
-
currentRuntime = previousRuntime;
|
|
396
|
-
currentInstance = previousInstance;
|
|
509
|
+
hookRenderState.currentRuntime = previousRuntime;
|
|
510
|
+
hookRenderState.currentInstance = previousInstance;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export function hasChangedContextDependency(
|
|
515
|
+
runtime: RootRuntime,
|
|
516
|
+
keys: readonly string[],
|
|
517
|
+
): boolean {
|
|
518
|
+
for (const key of keys) {
|
|
519
|
+
const dependencies = runtime.instances.get(key)?.contextDependencies;
|
|
520
|
+
|
|
521
|
+
if (dependencies === undefined) {
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
for (const [context, value] of dependencies) {
|
|
526
|
+
if (!Object.is(readContextValue(context), value)) {
|
|
527
|
+
return true;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
397
530
|
}
|
|
531
|
+
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
export function hasContextDependency(
|
|
536
|
+
runtime: RootRuntime,
|
|
537
|
+
keys: readonly string[],
|
|
538
|
+
): boolean {
|
|
539
|
+
return keys.some((key) => runtime.instances.get(key)?.contextDependencies !== undefined);
|
|
398
540
|
}
|
|
399
541
|
|
|
400
542
|
export function getDevToolsHookState(
|
|
@@ -426,10 +568,54 @@ export function renderWithStrictMode<T>(
|
|
|
426
568
|
}
|
|
427
569
|
}
|
|
428
570
|
|
|
571
|
+
export function renderWithStrictModeMemoCapture<T>(
|
|
572
|
+
runtime: RootRuntime,
|
|
573
|
+
render: () => T,
|
|
574
|
+
): { result: T; memoValues: readonly unknown[]; memoValuesByHook: ReadonlyMap<string, unknown> } {
|
|
575
|
+
const previousCapture = runtime.strictMemoCapture;
|
|
576
|
+
const previousCaptureByHook = runtime.strictMemoCaptureByHook;
|
|
577
|
+
runtime.strictMemoCapture = [];
|
|
578
|
+
runtime.strictMemoCaptureByHook = new Map();
|
|
579
|
+
|
|
580
|
+
try {
|
|
581
|
+
const result = renderWithStrictMode(runtime, render);
|
|
582
|
+
return {
|
|
583
|
+
result,
|
|
584
|
+
memoValues: runtime.strictMemoCapture,
|
|
585
|
+
memoValuesByHook: runtime.strictMemoCaptureByHook,
|
|
586
|
+
};
|
|
587
|
+
} finally {
|
|
588
|
+
runtime.strictMemoCapture = previousCapture;
|
|
589
|
+
runtime.strictMemoCaptureByHook = previousCaptureByHook;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
export function renderStrictModeReplay<T>(
|
|
594
|
+
runtime: RootRuntime,
|
|
595
|
+
memoValues: readonly unknown[],
|
|
596
|
+
memoValuesByHook: ReadonlyMap<string, unknown>,
|
|
597
|
+
render: () => T,
|
|
598
|
+
): T {
|
|
599
|
+
const previousReplay = runtime.strictMemoReplay;
|
|
600
|
+
const previousReplayByHook = runtime.strictMemoReplayByHook;
|
|
601
|
+
runtime.strictReplayDepth += 1;
|
|
602
|
+
runtime.strictMemoReplay = { values: memoValues, index: 0 };
|
|
603
|
+
runtime.strictMemoReplayByHook = memoValuesByHook;
|
|
604
|
+
|
|
605
|
+
try {
|
|
606
|
+
return render();
|
|
607
|
+
} finally {
|
|
608
|
+
runtime.strictMemoReplay = previousReplay;
|
|
609
|
+
runtime.strictMemoReplayByHook = previousReplayByHook;
|
|
610
|
+
runtime.strictReplayDepth -= 1;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
429
614
|
export function takeRuntimeSnapshot(runtime: RootRuntime): RuntimeSnapshot {
|
|
430
615
|
return {
|
|
431
616
|
instanceKeys: new Set(runtime.instances.keys()),
|
|
432
617
|
portalContainers: new Set(runtime.portalContainers),
|
|
618
|
+
portalNodes: clonePortalNodes(runtime.portalNodes),
|
|
433
619
|
pendingInsertionEffectsLength: runtime.pendingInsertionEffects.length,
|
|
434
620
|
pendingLayoutEffectsLength: runtime.pendingLayoutEffects.length,
|
|
435
621
|
pendingEffectsLength: runtime.pendingEffects.length,
|
|
@@ -439,6 +625,11 @@ export function takeRuntimeSnapshot(runtime: RootRuntime): RuntimeSnapshot {
|
|
|
439
625
|
identifierPrefix: runtime.identifierPrefix,
|
|
440
626
|
idMode: runtime.idMode,
|
|
441
627
|
strictModeDepth: runtime.strictModeDepth,
|
|
628
|
+
strictReplayDepth: runtime.strictReplayDepth,
|
|
629
|
+
strictMemoCapture: runtime.strictMemoCapture,
|
|
630
|
+
strictMemoCaptureByHook: runtime.strictMemoCaptureByHook,
|
|
631
|
+
strictMemoReplay: runtime.strictMemoReplay,
|
|
632
|
+
strictMemoReplayByHook: runtime.strictMemoReplayByHook,
|
|
442
633
|
profilerFlushDepth: runtime.profilerFlushDepth,
|
|
443
634
|
};
|
|
444
635
|
}
|
|
@@ -456,6 +647,11 @@ export function restoreRuntimeSnapshot(
|
|
|
456
647
|
runtime.identifierPrefix = snapshot.identifierPrefix;
|
|
457
648
|
runtime.idMode = snapshot.idMode;
|
|
458
649
|
runtime.strictModeDepth = snapshot.strictModeDepth;
|
|
650
|
+
runtime.strictReplayDepth = snapshot.strictReplayDepth;
|
|
651
|
+
runtime.strictMemoCapture = snapshot.strictMemoCapture;
|
|
652
|
+
runtime.strictMemoCaptureByHook = snapshot.strictMemoCaptureByHook;
|
|
653
|
+
runtime.strictMemoReplay = snapshot.strictMemoReplay;
|
|
654
|
+
runtime.strictMemoReplayByHook = snapshot.strictMemoReplayByHook;
|
|
459
655
|
runtime.profilerFlushDepth = snapshot.profilerFlushDepth;
|
|
460
656
|
|
|
461
657
|
for (const key of runtime.instances.keys()) {
|
|
@@ -464,16 +660,48 @@ export function restoreRuntimeSnapshot(
|
|
|
464
660
|
}
|
|
465
661
|
}
|
|
466
662
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
663
|
+
clearRuntimePortalNodesExcept(runtime, snapshot.portalNodes);
|
|
664
|
+
runtime.portalContainers.clear();
|
|
665
|
+
for (const container of snapshot.portalContainers) {
|
|
666
|
+
runtime.portalContainers.add(container);
|
|
667
|
+
}
|
|
668
|
+
runtime.portalNodes = clonePortalNodes(snapshot.portalNodes);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
export function clearRuntimePortalNodes(runtime: RootRuntime): void {
|
|
672
|
+
for (const [container, nodes] of runtime.portalNodes) {
|
|
673
|
+
for (const node of nodes) {
|
|
674
|
+
removeChildIfPresent(container, node);
|
|
470
675
|
}
|
|
471
676
|
}
|
|
472
677
|
|
|
678
|
+
runtime.portalNodes.clear();
|
|
473
679
|
runtime.portalContainers.clear();
|
|
474
|
-
|
|
475
|
-
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function clearRuntimePortalNodesExcept(
|
|
683
|
+
runtime: RootRuntime,
|
|
684
|
+
preserved: Map<Element, Set<Node>>,
|
|
685
|
+
): void {
|
|
686
|
+
for (const [container, nodes] of runtime.portalNodes) {
|
|
687
|
+
const preservedNodes = preserved.get(container);
|
|
688
|
+
|
|
689
|
+
for (const node of nodes) {
|
|
690
|
+
if (preservedNodes?.has(node) !== true) {
|
|
691
|
+
removeChildIfPresent(container, node);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function clonePortalNodes(source: Map<Element, Set<Node>>): Map<Element, Set<Node>> {
|
|
698
|
+
const clone = new Map<Element, Set<Node>>();
|
|
699
|
+
|
|
700
|
+
for (const [container, nodes] of source) {
|
|
701
|
+
clone.set(container, new Set(nodes));
|
|
476
702
|
}
|
|
703
|
+
|
|
704
|
+
return clone;
|
|
477
705
|
}
|
|
478
706
|
|
|
479
707
|
export function useState<T>(
|
|
@@ -499,6 +727,7 @@ export function useState<T>(
|
|
|
499
727
|
}
|
|
500
728
|
|
|
501
729
|
const setState = (value: T | ((previous: T) => T)): void => {
|
|
730
|
+
const previousValue = slot.value;
|
|
502
731
|
const nextValue =
|
|
503
732
|
typeof value === "function"
|
|
504
733
|
? (value as (previous: T) => T)(slot.value as T)
|
|
@@ -508,7 +737,17 @@ export function useState<T>(
|
|
|
508
737
|
return;
|
|
509
738
|
}
|
|
510
739
|
|
|
740
|
+
if (hookRenderState.hostCommitDepth > 0 && !Object.hasOwn(slot, "hostCommitValue")) {
|
|
741
|
+
slot.hostCommitValue = previousValue;
|
|
742
|
+
}
|
|
743
|
+
|
|
511
744
|
slot.value = nextValue;
|
|
745
|
+
if (hookRenderState.hostCommitDepth > 0) {
|
|
746
|
+
updateHostCommitDirtyState(instance);
|
|
747
|
+
hookRenderState.queuedHostCommitRerenders.add(runtime);
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
|
|
512
751
|
scheduleInstanceUpdate(runtime, instance);
|
|
513
752
|
};
|
|
514
753
|
|
|
@@ -616,6 +855,7 @@ export function useImperativeHandle<T>(
|
|
|
616
855
|
}
|
|
617
856
|
|
|
618
857
|
export function useMemo<T>(factory: () => T, deps?: readonly unknown[]): T {
|
|
858
|
+
const runtime = requireRuntime();
|
|
619
859
|
const instance = requireInstance();
|
|
620
860
|
const index = instance.hookIndex;
|
|
621
861
|
instance.hookIndex += 1;
|
|
@@ -626,25 +866,82 @@ export function useMemo<T>(factory: () => T, deps?: readonly unknown[]): T {
|
|
|
626
866
|
throw new Error("Hook order changed between renders.");
|
|
627
867
|
}
|
|
628
868
|
|
|
629
|
-
|
|
869
|
+
let value: unknown;
|
|
870
|
+
const shouldRecompute =
|
|
630
871
|
slot === undefined ||
|
|
631
872
|
deps === undefined ||
|
|
632
873
|
slot.deps === undefined ||
|
|
633
|
-
!areHookInputsEqual(deps, slot.deps)
|
|
634
|
-
|
|
635
|
-
|
|
874
|
+
!areHookInputsEqual(deps, slot.deps);
|
|
875
|
+
|
|
876
|
+
if (runtime.strictReplayDepth > 0) {
|
|
877
|
+
const replayValue = factory();
|
|
878
|
+
if (slot === undefined) {
|
|
879
|
+
slot =
|
|
880
|
+
deps === undefined
|
|
881
|
+
? { kind: "memo", value: replayValue }
|
|
882
|
+
: { kind: "memo", value: replayValue, deps };
|
|
883
|
+
instance.hooks[index] = slot;
|
|
884
|
+
}
|
|
885
|
+
const hookKey = getStrictMemoHookKey(instance, index);
|
|
886
|
+
const replayByHook = runtime.strictMemoReplayByHook;
|
|
887
|
+
const replay = runtime.strictMemoReplay;
|
|
888
|
+
value = replayByHook?.has(hookKey) === true
|
|
889
|
+
? replayByHook.get(hookKey)
|
|
890
|
+
: replay === undefined || replay.index >= replay.values.length
|
|
891
|
+
? slot.value
|
|
892
|
+
: replay.values[replay.index++];
|
|
893
|
+
} else if (shouldRecompute) {
|
|
894
|
+
value = factory();
|
|
636
895
|
slot =
|
|
637
896
|
deps === undefined
|
|
638
897
|
? { kind: "memo", value }
|
|
639
898
|
: { kind: "memo", value, deps };
|
|
640
899
|
instance.hooks[index] = slot;
|
|
900
|
+
} else {
|
|
901
|
+
value = slot!.value;
|
|
641
902
|
}
|
|
642
903
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
904
|
+
if (runtime.strictModeDepth > 0 && runtime.strictReplayDepth === 0) {
|
|
905
|
+
runtime.strictMemoCapture?.push(value);
|
|
906
|
+
runtime.strictMemoCaptureByHook?.set(getStrictMemoHookKey(instance, index), value);
|
|
907
|
+
}
|
|
646
908
|
|
|
647
|
-
|
|
909
|
+
const memoSlot = slot;
|
|
910
|
+
if (memoSlot === undefined) {
|
|
911
|
+
throw new Error("Hook order changed between renders.");
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
recordDevToolsHook("useMemo", memoSlot.deps === undefined
|
|
915
|
+
? { kind: "memo", value }
|
|
916
|
+
: { kind: "memo", value, deps: memoSlot.deps });
|
|
917
|
+
|
|
918
|
+
return value as T;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
function getStrictMemoHookKey(
|
|
922
|
+
instance: ComponentInstance,
|
|
923
|
+
index: number,
|
|
924
|
+
): string {
|
|
925
|
+
return `${instance.path}:${getStrictMemoOwnerId(instance.owner)}:${index}`;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
function getStrictMemoOwnerId(owner: unknown): number {
|
|
929
|
+
if ((typeof owner === "object" && owner !== null) || typeof owner === "function") {
|
|
930
|
+
const objectOwner = owner as object;
|
|
931
|
+
let ownerId = strictMemoObjectOwnerIds.get(objectOwner);
|
|
932
|
+
if (ownerId === undefined) {
|
|
933
|
+
ownerId = strictMemoOwnerId++;
|
|
934
|
+
strictMemoObjectOwnerIds.set(objectOwner, ownerId);
|
|
935
|
+
}
|
|
936
|
+
return ownerId;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
let ownerId = strictMemoPrimitiveOwnerIds.get(owner);
|
|
940
|
+
if (ownerId === undefined) {
|
|
941
|
+
ownerId = strictMemoOwnerId++;
|
|
942
|
+
strictMemoPrimitiveOwnerIds.set(owner, ownerId);
|
|
943
|
+
}
|
|
944
|
+
return ownerId;
|
|
648
945
|
}
|
|
649
946
|
|
|
650
947
|
function assignRef<T>(ref: unknown, value: T | null): void {
|
|
@@ -659,7 +956,7 @@ function assignRef<T>(ref: unknown, value: T | null): void {
|
|
|
659
956
|
}
|
|
660
957
|
|
|
661
958
|
function recordDevToolsHook(type: string, value: DevToolsHookValue): void {
|
|
662
|
-
const instance = currentInstance;
|
|
959
|
+
const instance = hookRenderState.currentInstance;
|
|
663
960
|
|
|
664
961
|
if (instance === undefined || instance.devToolsHookSuppressionDepth > 0) {
|
|
665
962
|
return;
|
|
@@ -797,16 +1094,32 @@ export function useSyncExternalStore<T>(
|
|
|
797
1094
|
|
|
798
1095
|
runWithoutDevToolsHookTracking(() => useEffect(() => {
|
|
799
1096
|
const checkForUpdates = (): void => {
|
|
1097
|
+
if (instance.disposed === true) {
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
800
1101
|
const nextSnapshot = getSnapshot();
|
|
801
1102
|
|
|
802
1103
|
if (!Object.is(slot.value, nextSnapshot)) {
|
|
803
1104
|
slot.value = nextSnapshot;
|
|
1105
|
+
instance.dirty = true;
|
|
1106
|
+
runtime.externalStoreUpdate = true;
|
|
1107
|
+
if (runtime.profilerFlushDepth > 0) {
|
|
1108
|
+
hookRenderState.queuedEffectFlushRerenders.add(runtime);
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
804
1111
|
runtime.rerender("sync");
|
|
805
1112
|
}
|
|
806
1113
|
};
|
|
807
1114
|
|
|
808
|
-
|
|
809
|
-
|
|
1115
|
+
if (slot.hasMounted !== true) {
|
|
1116
|
+
checkForUpdates();
|
|
1117
|
+
}
|
|
1118
|
+
const unsubscribe = subscribe(checkForUpdates);
|
|
1119
|
+
slot.hasMounted = true;
|
|
1120
|
+
return () => {
|
|
1121
|
+
unsubscribe();
|
|
1122
|
+
};
|
|
810
1123
|
}, [subscribe, getSnapshot]));
|
|
811
1124
|
|
|
812
1125
|
recordDevToolsHook("useSyncExternalStore", {
|
|
@@ -981,418 +1294,6 @@ export function hasStableExternalStores(
|
|
|
981
1294
|
);
|
|
982
1295
|
}
|
|
983
1296
|
|
|
984
|
-
export function renderToString<TProps>(
|
|
985
|
-
component:
|
|
986
|
-
| ((props: TProps) => ReactCompatNode)
|
|
987
|
-
| (new (props: TProps) => { render(): ReactCompatNode }),
|
|
988
|
-
props?: TProps,
|
|
989
|
-
options: RootRuntimeOptions = {},
|
|
990
|
-
): string {
|
|
991
|
-
const runtime = createRootRuntime(() => undefined, {
|
|
992
|
-
...options,
|
|
993
|
-
idMode: "server",
|
|
994
|
-
});
|
|
995
|
-
|
|
996
|
-
return runWithCacheScope(createCacheScope(), () => {
|
|
997
|
-
try {
|
|
998
|
-
const rendered = renderWithRootRuntime(runtime, "0", () => {
|
|
999
|
-
if (isClassComponentType(component)) {
|
|
1000
|
-
const instance = new component(props as Record<string, unknown>);
|
|
1001
|
-
return instance.render();
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
return (component as (props: TProps) => ReactCompatNode)(props as TProps);
|
|
1005
|
-
});
|
|
1006
|
-
return typeof rendered === "string"
|
|
1007
|
-
? rendered
|
|
1008
|
-
: renderNodeToString(rendered, runtime, "0");
|
|
1009
|
-
} finally {
|
|
1010
|
-
runtime.dispose();
|
|
1011
|
-
}
|
|
1012
|
-
});
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
function renderNodeToString(
|
|
1016
|
-
node: ReactCompatNode,
|
|
1017
|
-
runtime: RootRuntime,
|
|
1018
|
-
path: string,
|
|
1019
|
-
): string {
|
|
1020
|
-
if (node === null || node === undefined || typeof node === "boolean") {
|
|
1021
|
-
return "";
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
if (typeof node === "string" || typeof node === "number") {
|
|
1025
|
-
return escapeHtml(node);
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
if (Array.isArray(node)) {
|
|
1029
|
-
return node.map((child, index) => renderNodeToString(child, runtime, `${path}.${index}`)).join("");
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
if (!isReactCompatElement(node)) {
|
|
1033
|
-
return "";
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
return renderElementToString(node, runtime, path);
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
function renderElementToString(
|
|
1040
|
-
element: ReactCompatElement,
|
|
1041
|
-
runtime: RootRuntime,
|
|
1042
|
-
path: string,
|
|
1043
|
-
): string {
|
|
1044
|
-
if (typeof element.type === "string") {
|
|
1045
|
-
if (element.type === "textarea") {
|
|
1046
|
-
return renderTextareaToString(element, runtime, path);
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
if (element.type === "select") {
|
|
1050
|
-
return renderSelectToString(element, runtime, path);
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
const attributes = element.type === "input"
|
|
1054
|
-
? renderInputAttributesToString(element.props)
|
|
1055
|
-
: Object.entries(element.props)
|
|
1056
|
-
.map(([name, value]) => renderHtmlAttribute(name, value))
|
|
1057
|
-
.filter((attribute) => attribute !== "")
|
|
1058
|
-
.join("");
|
|
1059
|
-
if (voidHtmlElements.has(element.type)) {
|
|
1060
|
-
return `<${element.type}${attributes}/>`;
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
return `<${element.type}${attributes}>${renderNodeToString(element.props.children, runtime, `${path}.children`)}</${element.type}>`;
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
if (element.type === Fragment) {
|
|
1067
|
-
return renderNodeToString(element.props.children, runtime, `${path}.fragment`);
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
if (element.type === Activity) {
|
|
1071
|
-
if ((element.props as { mode?: unknown }).mode === "hidden") {
|
|
1072
|
-
return "";
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
return `<!--&-->${renderNodeToString(element.props.children, runtime, `${path}.activity`)}<!--/&-->`;
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
if (element.type === Profiler) {
|
|
1079
|
-
return renderNodeToString(element.props.children, runtime, `${path}.profiler`);
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
if (isReactCompatProvider(element.type)) {
|
|
1083
|
-
return renderWithContextProvider(
|
|
1084
|
-
element.type,
|
|
1085
|
-
(element.props as { value?: unknown }).value,
|
|
1086
|
-
() => renderNodeToString(element.props.children, runtime, `${path}.provider`),
|
|
1087
|
-
);
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
if (isReactCompatConsumer(element.type)) {
|
|
1091
|
-
const children = element.props.children;
|
|
1092
|
-
|
|
1093
|
-
if (typeof children === "function") {
|
|
1094
|
-
return renderNodeToString(
|
|
1095
|
-
(children as (value: unknown) => ReactCompatNode)(useContext(element.type.context)),
|
|
1096
|
-
runtime,
|
|
1097
|
-
`${path}.consumer`,
|
|
1098
|
-
);
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
return "";
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
if (isForwardRefType(element.type)) {
|
|
1105
|
-
const forwardRefType = element.type;
|
|
1106
|
-
return renderNodeToString(
|
|
1107
|
-
renderWithRootRuntime(runtime, `${path}.forwardRef`, () =>
|
|
1108
|
-
forwardRefType.render(element.props, element.ref),
|
|
1109
|
-
),
|
|
1110
|
-
runtime,
|
|
1111
|
-
`${path}.forwardRef`,
|
|
1112
|
-
);
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
if (isMemoType(element.type)) {
|
|
1116
|
-
return renderNodeToString(
|
|
1117
|
-
{
|
|
1118
|
-
...element,
|
|
1119
|
-
type: element.type.type,
|
|
1120
|
-
},
|
|
1121
|
-
runtime,
|
|
1122
|
-
`${path}.memo`,
|
|
1123
|
-
);
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
if (isClassComponentType(element.type)) {
|
|
1127
|
-
const instance = new element.type(element.props);
|
|
1128
|
-
return renderNodeToString(
|
|
1129
|
-
renderWithRootRuntime(runtime, path, () => instance.render()),
|
|
1130
|
-
runtime,
|
|
1131
|
-
path,
|
|
1132
|
-
);
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
if (typeof element.type === "function") {
|
|
1136
|
-
const component = element.type as (props: typeof element.props) => ReactCompatNode;
|
|
1137
|
-
return renderNodeToString(
|
|
1138
|
-
renderWithRootRuntime(runtime, path, () => component(element.props)),
|
|
1139
|
-
runtime,
|
|
1140
|
-
path,
|
|
1141
|
-
);
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
return "";
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
function isClassComponentType(
|
|
1148
|
-
value: unknown,
|
|
1149
|
-
): value is new (props: Record<string, unknown>) => { render(): ReactCompatNode } {
|
|
1150
|
-
return (
|
|
1151
|
-
typeof value === "function" &&
|
|
1152
|
-
typeof (value as { prototype?: { render?: unknown } }).prototype?.render === "function"
|
|
1153
|
-
);
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
function renderTextareaToString(
|
|
1157
|
-
element: ReactCompatElement,
|
|
1158
|
-
runtime: RootRuntime,
|
|
1159
|
-
path: string,
|
|
1160
|
-
): string {
|
|
1161
|
-
const value =
|
|
1162
|
-
(element.props as { value?: unknown; defaultValue?: unknown }).value ??
|
|
1163
|
-
(element.props as { value?: unknown; defaultValue?: unknown }).defaultValue ??
|
|
1164
|
-
element.props.children;
|
|
1165
|
-
const attributes = Object.entries(element.props)
|
|
1166
|
-
.filter(([name]) => name !== "value" && name !== "defaultValue")
|
|
1167
|
-
.map(([name, child]) => renderHtmlAttribute(name, child))
|
|
1168
|
-
.filter((attribute) => attribute !== "")
|
|
1169
|
-
.join("");
|
|
1170
|
-
|
|
1171
|
-
return `<textarea${attributes}>${renderNodeToString(value as ReactCompatNode, runtime, `${path}.textarea`)}</textarea>`;
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
function renderSelectToString(
|
|
1175
|
-
element: ReactCompatElement,
|
|
1176
|
-
runtime: RootRuntime,
|
|
1177
|
-
path: string,
|
|
1178
|
-
): string {
|
|
1179
|
-
const selectedValue =
|
|
1180
|
-
(element.props as { value?: unknown; defaultValue?: unknown }).value ??
|
|
1181
|
-
(element.props as { value?: unknown; defaultValue?: unknown }).defaultValue;
|
|
1182
|
-
const attributes = Object.entries(element.props)
|
|
1183
|
-
.filter(([name]) => name !== "value" && name !== "defaultValue")
|
|
1184
|
-
.map(([name, child]) => renderHtmlAttribute(name, child))
|
|
1185
|
-
.filter((attribute) => attribute !== "")
|
|
1186
|
-
.join("");
|
|
1187
|
-
|
|
1188
|
-
return `<select${attributes}>${renderSelectChildrenToString(
|
|
1189
|
-
element.props.children,
|
|
1190
|
-
selectedValue,
|
|
1191
|
-
runtime,
|
|
1192
|
-
`${path}.select`,
|
|
1193
|
-
)}</select>`;
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
function renderSelectChildrenToString(
|
|
1197
|
-
children: ReactCompatNode,
|
|
1198
|
-
selectedValue: unknown,
|
|
1199
|
-
runtime: RootRuntime,
|
|
1200
|
-
path: string,
|
|
1201
|
-
): string {
|
|
1202
|
-
const childArray = Array.isArray(children) ? children : [children];
|
|
1203
|
-
|
|
1204
|
-
return childArray.map((child, index) => {
|
|
1205
|
-
if (!isReactCompatElement(child) || child.type !== "option") {
|
|
1206
|
-
return renderNodeToString(child, runtime, `${path}.${index}`);
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
const optionValue =
|
|
1210
|
-
(child.props as { value?: unknown }).value ?? child.props.children;
|
|
1211
|
-
const selected =
|
|
1212
|
-
selectedValue !== undefined && String(optionValue) === String(selectedValue);
|
|
1213
|
-
const props = selected
|
|
1214
|
-
? { ...child.props, selected: true }
|
|
1215
|
-
: child.props;
|
|
1216
|
-
|
|
1217
|
-
return renderElementToString({ ...child, props }, runtime, `${path}.${index}`);
|
|
1218
|
-
}).join("");
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
function renderInputAttributesToString(props: Record<string, unknown>): string {
|
|
1222
|
-
const hasValue = props.value !== undefined;
|
|
1223
|
-
const hasChecked = props.checked !== undefined;
|
|
1224
|
-
|
|
1225
|
-
return Object.entries(props)
|
|
1226
|
-
.filter(([name]) =>
|
|
1227
|
-
!((name === "defaultValue" && hasValue) || (name === "defaultChecked" && hasChecked))
|
|
1228
|
-
)
|
|
1229
|
-
.sort(([leftName], [rightName]) =>
|
|
1230
|
-
Number(isInputValueAttribute(leftName)) - Number(isInputValueAttribute(rightName))
|
|
1231
|
-
)
|
|
1232
|
-
.map(([name, value]) => renderHtmlAttribute(toInputHtmlAttributeName(name), value))
|
|
1233
|
-
.filter((attribute) => attribute !== "")
|
|
1234
|
-
.join("");
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
function renderHtmlAttribute(name: string, value: unknown): string {
|
|
1238
|
-
if (
|
|
1239
|
-
name === "children" ||
|
|
1240
|
-
name === "key" ||
|
|
1241
|
-
name === "ref" ||
|
|
1242
|
-
/^on[A-Z]/.test(name) ||
|
|
1243
|
-
value === null ||
|
|
1244
|
-
value === undefined ||
|
|
1245
|
-
value === false ||
|
|
1246
|
-
typeof value === "function"
|
|
1247
|
-
) {
|
|
1248
|
-
return "";
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
|
-
if (name === "style") {
|
|
1252
|
-
const style = renderStyleAttribute(value);
|
|
1253
|
-
return style === "" ? "" : ` style="${escapeHtml(style)}"`;
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
const attributeName = toHtmlAttributeName(name);
|
|
1257
|
-
if (isDangerousHtmlAttribute(attributeName)) {
|
|
1258
|
-
return isDangerousHtmlOptIn(value)
|
|
1259
|
-
? ` ${attributeName}="${escapeHtml(value.__html)}"`
|
|
1260
|
-
: "";
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
if (typeof value === "object") {
|
|
1264
|
-
return "";
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
if (value === true) {
|
|
1268
|
-
return ` ${attributeName}=""`;
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
return ` ${attributeName}="${escapeHtml(value)}"`;
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
function isInputValueAttribute(name: string): boolean {
|
|
1275
|
-
return name === "value" || name === "defaultValue";
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
function toInputHtmlAttributeName(name: string): string {
|
|
1279
|
-
if (name === "defaultValue") {
|
|
1280
|
-
return "value";
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
if (name === "defaultChecked") {
|
|
1284
|
-
return "checked";
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
|
-
return name;
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
function toHtmlAttributeName(name: string): string {
|
|
1291
|
-
return HTML_ATTRIBUTE_ALIASES[name] ?? name;
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
const HTML_ATTRIBUTE_ALIASES: Record<string, string> = {
|
|
1295
|
-
acceptCharset: "accept-charset",
|
|
1296
|
-
autoFocus: "autofocus",
|
|
1297
|
-
autoPlay: "autoplay",
|
|
1298
|
-
charSet: "charset",
|
|
1299
|
-
className: "class",
|
|
1300
|
-
colSpan: "colspan",
|
|
1301
|
-
contentEditable: "contenteditable",
|
|
1302
|
-
crossOrigin: "crossorigin",
|
|
1303
|
-
encType: "enctype",
|
|
1304
|
-
formAction: "formaction",
|
|
1305
|
-
frameBorder: "frameborder",
|
|
1306
|
-
htmlFor: "for",
|
|
1307
|
-
httpEquiv: "http-equiv",
|
|
1308
|
-
maxLength: "maxlength",
|
|
1309
|
-
minLength: "minlength",
|
|
1310
|
-
noValidate: "novalidate",
|
|
1311
|
-
playsInline: "playsinline",
|
|
1312
|
-
readOnly: "readOnly",
|
|
1313
|
-
rowSpan: "rowspan",
|
|
1314
|
-
spellCheck: "spellcheck",
|
|
1315
|
-
srcDoc: "srcdoc",
|
|
1316
|
-
srcSet: "srcset",
|
|
1317
|
-
tabIndex: "tabindex",
|
|
1318
|
-
useMap: "usemap",
|
|
1319
|
-
};
|
|
1320
|
-
|
|
1321
|
-
function renderStyleAttribute(value: unknown): string {
|
|
1322
|
-
if (typeof value !== "object" || value === null) {
|
|
1323
|
-
return "";
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
return Object.entries(value)
|
|
1327
|
-
.filter(([, propertyValue]) =>
|
|
1328
|
-
propertyValue !== null &&
|
|
1329
|
-
propertyValue !== undefined &&
|
|
1330
|
-
typeof propertyValue !== "boolean" &&
|
|
1331
|
-
propertyValue !== "",
|
|
1332
|
-
)
|
|
1333
|
-
.map(([name, propertyValue]) =>
|
|
1334
|
-
`${toKebabCase(name)}:${renderCssValue(name, propertyValue)}`,
|
|
1335
|
-
)
|
|
1336
|
-
.join(";");
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1339
|
-
function renderCssValue(name: string, value: unknown): string {
|
|
1340
|
-
if (typeof value !== "number" || value === 0 || isUnitlessCssProperty(name)) {
|
|
1341
|
-
return String(value);
|
|
1342
|
-
}
|
|
1343
|
-
|
|
1344
|
-
return `${value}px`;
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
|
-
function toKebabCase(value: string): string {
|
|
1348
|
-
return value.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
function isUnitlessCssProperty(name: string): boolean {
|
|
1352
|
-
return (
|
|
1353
|
-
name === "flex" ||
|
|
1354
|
-
name === "fontWeight" ||
|
|
1355
|
-
name === "lineHeight" ||
|
|
1356
|
-
name === "opacity" ||
|
|
1357
|
-
name === "order" ||
|
|
1358
|
-
name === "zIndex" ||
|
|
1359
|
-
name === "zoom"
|
|
1360
|
-
);
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
const voidHtmlElements = new Set([
|
|
1364
|
-
"area",
|
|
1365
|
-
"base",
|
|
1366
|
-
"br",
|
|
1367
|
-
"col",
|
|
1368
|
-
"embed",
|
|
1369
|
-
"hr",
|
|
1370
|
-
"img",
|
|
1371
|
-
"input",
|
|
1372
|
-
"link",
|
|
1373
|
-
"meta",
|
|
1374
|
-
"param",
|
|
1375
|
-
"source",
|
|
1376
|
-
"track",
|
|
1377
|
-
"wbr",
|
|
1378
|
-
]);
|
|
1379
|
-
|
|
1380
|
-
function isForwardRefType(value: unknown): value is ForwardRefType {
|
|
1381
|
-
return (
|
|
1382
|
-
typeof value === "object" &&
|
|
1383
|
-
value !== null &&
|
|
1384
|
-
(value as { $$typeof?: unknown }).$$typeof === FORWARD_REF_TYPE
|
|
1385
|
-
);
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
|
-
function isMemoType(value: unknown): value is MemoType {
|
|
1389
|
-
return (
|
|
1390
|
-
typeof value === "object" &&
|
|
1391
|
-
value !== null &&
|
|
1392
|
-
(value as { $$typeof?: unknown }).$$typeof === MEMO_TYPE
|
|
1393
|
-
);
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
1297
|
function readThenable<T>(thenable: PromiseLike<T>): T {
|
|
1397
1298
|
const record = thenable as PromiseLike<T> & {
|
|
1398
1299
|
status?: "pending" | "fulfilled" | "rejected";
|
|
@@ -1482,6 +1383,15 @@ export function flushSyncUpdates<T>(callback: () => T): T {
|
|
|
1482
1383
|
}
|
|
1483
1384
|
}
|
|
1484
1385
|
|
|
1386
|
+
export function runWithHostCommit<T>(callback: () => T): T {
|
|
1387
|
+
hookRenderState.hostCommitDepth += 1;
|
|
1388
|
+
try {
|
|
1389
|
+
return callback();
|
|
1390
|
+
} finally {
|
|
1391
|
+
hookRenderState.hostCommitDepth -= 1;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1485
1395
|
export function useTransition(): [boolean, StartTransition] {
|
|
1486
1396
|
const [pending, setPending] = runWithoutDevToolsHookTracking(() => useState(false));
|
|
1487
1397
|
const startTransitionWithPending: StartTransition = (scope) => {
|
|
@@ -1640,6 +1550,7 @@ function useEffectImpl(
|
|
|
1640
1550
|
|
|
1641
1551
|
const shouldRun =
|
|
1642
1552
|
slot === undefined ||
|
|
1553
|
+
slot.mounted !== true ||
|
|
1643
1554
|
deps === undefined ||
|
|
1644
1555
|
slot.deps === undefined ||
|
|
1645
1556
|
!areHookInputsEqual(deps, slot.deps);
|
|
@@ -1663,7 +1574,8 @@ function useEffectImpl(
|
|
|
1663
1574
|
}
|
|
1664
1575
|
|
|
1665
1576
|
slot.strictReplay =
|
|
1666
|
-
runtime.strictModeDepth > 0
|
|
1577
|
+
(runtime.strictModeDepth > 0 || runtime.strictReplayDepth > 0) &&
|
|
1578
|
+
effectKind !== "insertion";
|
|
1667
1579
|
|
|
1668
1580
|
if (shouldRun) {
|
|
1669
1581
|
const queue =
|
|
@@ -1680,7 +1592,7 @@ function recordExternalStoreCheck<T>(
|
|
|
1680
1592
|
getSnapshot: () => T,
|
|
1681
1593
|
value: T,
|
|
1682
1594
|
): void {
|
|
1683
|
-
currentRuntime?.externalStoreChecks.push({ getSnapshot, value });
|
|
1595
|
+
hookRenderState.currentRuntime?.externalStoreChecks.push({ getSnapshot, value });
|
|
1684
1596
|
}
|
|
1685
1597
|
|
|
1686
1598
|
function flushPendingEffects(queue: PendingEffect[]): PendingEffect[] {
|
|
@@ -1701,6 +1613,7 @@ function flushPendingEffects(queue: PendingEffect[]): PendingEffect[] {
|
|
|
1701
1613
|
} else {
|
|
1702
1614
|
delete slot.cleanup;
|
|
1703
1615
|
}
|
|
1616
|
+
slot.mounted = true;
|
|
1704
1617
|
|
|
1705
1618
|
if (shouldReplay) {
|
|
1706
1619
|
strictReplay.push({ slot });
|
|
@@ -1795,9 +1708,21 @@ function scheduleInstanceUpdate(
|
|
|
1795
1708
|
runtime: RootRuntime,
|
|
1796
1709
|
instance: ComponentInstance,
|
|
1797
1710
|
): void {
|
|
1711
|
+
if (instance.disposed === true) {
|
|
1712
|
+
return;
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1798
1715
|
instance.dirty = true;
|
|
1799
1716
|
if (transitionDepth === 0) {
|
|
1800
1717
|
syncVersion += 1;
|
|
1718
|
+
if (hookRenderState.hostCommitDepth > 0) {
|
|
1719
|
+
hookRenderState.queuedHostCommitRerenders.add(runtime);
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
if (runtime.effectFlushPhase !== undefined) {
|
|
1723
|
+
hookRenderState.queuedEffectFlushRerenders.add(runtime);
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1801
1726
|
if (eventBatchDepth > 0) {
|
|
1802
1727
|
queueEventRerender(runtime);
|
|
1803
1728
|
return;
|
|
@@ -1811,6 +1736,82 @@ function scheduleInstanceUpdate(
|
|
|
1811
1736
|
}
|
|
1812
1737
|
}
|
|
1813
1738
|
|
|
1739
|
+
function flushHostCommitRerenders(): void {
|
|
1740
|
+
if (
|
|
1741
|
+
hookRenderState.hostCommitDepth > 0 ||
|
|
1742
|
+
hookRenderState.queuedHostCommitRerenders.size === 0
|
|
1743
|
+
) {
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
const runtimes = [...hookRenderState.queuedHostCommitRerenders];
|
|
1748
|
+
hookRenderState.queuedHostCommitRerenders.clear();
|
|
1749
|
+
for (const runtime of runtimes) {
|
|
1750
|
+
const hasDirtyInstance = Array.from(runtime.instances.values()).some(
|
|
1751
|
+
(instance) => instance.dirty,
|
|
1752
|
+
);
|
|
1753
|
+
clearHostCommitStateBaselines(runtime);
|
|
1754
|
+
|
|
1755
|
+
if (hasDirtyInstance) {
|
|
1756
|
+
runtime.rerender("sync");
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
function flushEffectFlushRerenders(): void {
|
|
1762
|
+
if (
|
|
1763
|
+
effectFlushRerenderDepth > 0 ||
|
|
1764
|
+
hookRenderState.queuedEffectFlushRerenders.size === 0
|
|
1765
|
+
) {
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
effectFlushRerenderDepth += 1;
|
|
1770
|
+
try {
|
|
1771
|
+
for (
|
|
1772
|
+
let attempt = 0;
|
|
1773
|
+
attempt < 3 && hookRenderState.queuedEffectFlushRerenders.size > 0;
|
|
1774
|
+
attempt += 1
|
|
1775
|
+
) {
|
|
1776
|
+
const runtimes = [...hookRenderState.queuedEffectFlushRerenders];
|
|
1777
|
+
hookRenderState.queuedEffectFlushRerenders.clear();
|
|
1778
|
+
for (const runtime of runtimes) {
|
|
1779
|
+
const hasDirtyInstance = Array.from(runtime.instances.values()).some(
|
|
1780
|
+
(instance) => instance.dirty,
|
|
1781
|
+
);
|
|
1782
|
+
|
|
1783
|
+
if (hasDirtyInstance) {
|
|
1784
|
+
runtime.rerender("sync");
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
hookRenderState.queuedEffectFlushRerenders.clear();
|
|
1789
|
+
} finally {
|
|
1790
|
+
effectFlushRerenderDepth -= 1;
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
function updateHostCommitDirtyState(
|
|
1795
|
+
instance: ComponentInstance,
|
|
1796
|
+
): void {
|
|
1797
|
+
instance.dirty = instance.hooks.some(
|
|
1798
|
+
(slot) =>
|
|
1799
|
+
slot.kind === "state" &&
|
|
1800
|
+
Object.hasOwn(slot, "hostCommitValue") &&
|
|
1801
|
+
!Object.is(slot.hostCommitValue, slot.value),
|
|
1802
|
+
);
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
function clearHostCommitStateBaselines(runtime: RootRuntime): void {
|
|
1806
|
+
for (const instance of runtime.instances.values()) {
|
|
1807
|
+
for (const slot of instance.hooks) {
|
|
1808
|
+
if (slot.kind === "state") {
|
|
1809
|
+
delete slot.hostCommitValue;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1814
1815
|
function getCacheLeaf(
|
|
1815
1816
|
scope: CacheScope,
|
|
1816
1817
|
callback: (...args: never[]) => unknown,
|
|
@@ -1861,7 +1862,7 @@ function createCacheTrieNode(): CacheTrieNode {
|
|
|
1861
1862
|
}
|
|
1862
1863
|
|
|
1863
1864
|
function getCurrentCacheScope(): CacheScope | undefined {
|
|
1864
|
-
return currentCacheScope ?? getGlobalCacheScope();
|
|
1865
|
+
return hookRenderState.currentCacheScope ?? getGlobalCacheScope();
|
|
1865
1866
|
}
|
|
1866
1867
|
|
|
1867
1868
|
function getGlobalCacheScope(): CacheScope | undefined {
|
|
@@ -1901,9 +1902,11 @@ function cleanupInactiveInstances(runtime: RootRuntime): void {
|
|
|
1901
1902
|
}
|
|
1902
1903
|
|
|
1903
1904
|
function cleanupInstance(instance: ComponentInstance): void {
|
|
1905
|
+
instance.disposed = true;
|
|
1904
1906
|
for (const slot of instance.hooks) {
|
|
1905
1907
|
if (slot?.kind === "effect") {
|
|
1906
1908
|
slot.disposed = true;
|
|
1909
|
+
slot.mounted = false;
|
|
1907
1910
|
slot.cleanup?.();
|
|
1908
1911
|
delete slot.cleanup;
|
|
1909
1912
|
}
|
|
@@ -1911,19 +1914,19 @@ function cleanupInstance(instance: ComponentInstance): void {
|
|
|
1911
1914
|
}
|
|
1912
1915
|
|
|
1913
1916
|
function requireRuntime(): RootRuntime {
|
|
1914
|
-
if (currentRuntime === undefined) {
|
|
1917
|
+
if (hookRenderState.currentRuntime === undefined) {
|
|
1915
1918
|
throw new Error("Hooks can only be called while rendering.");
|
|
1916
1919
|
}
|
|
1917
1920
|
|
|
1918
|
-
return currentRuntime;
|
|
1921
|
+
return hookRenderState.currentRuntime;
|
|
1919
1922
|
}
|
|
1920
1923
|
|
|
1921
1924
|
function requireInstance(): ComponentInstance {
|
|
1922
|
-
if (currentInstance === undefined) {
|
|
1925
|
+
if (hookRenderState.currentInstance === undefined) {
|
|
1923
1926
|
throw new Error("Hooks can only be called while rendering.");
|
|
1924
1927
|
}
|
|
1925
1928
|
|
|
1926
|
-
return currentInstance;
|
|
1929
|
+
return hookRenderState.currentInstance;
|
|
1927
1930
|
}
|
|
1928
1931
|
|
|
1929
1932
|
function areHookInputsEqual(
|