@reckona/mreact-compat 0.0.171 → 0.0.173
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/dist/devtools.js +2 -0
- package/dist/devtools.js.map +1 -1
- package/dist/dom-host-rules.d.ts.map +1 -1
- package/dist/dom-host-rules.js +4 -1
- package/dist/dom-host-rules.js.map +1 -1
- package/dist/dom-props.js +2 -1
- package/dist/dom-props.js.map +1 -1
- package/dist/element.d.ts +13 -1
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +30 -2
- package/dist/element.js.map +1 -1
- package/dist/fiber-commit.js +2 -1
- package/dist/fiber-commit.js.map +1 -1
- package/dist/fiber-host.d.ts +1 -1
- package/dist/fiber-host.d.ts.map +1 -1
- package/dist/fiber-host.js +1 -1
- package/dist/fiber-host.js.map +1 -1
- package/dist/fiber.d.ts +2 -1
- package/dist/fiber.d.ts.map +1 -1
- package/dist/fiber.js +2 -0
- package/dist/fiber.js.map +1 -1
- package/dist/hooks.d.ts +9 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +127 -44
- package/dist/hooks.js.map +1 -1
- package/dist/host-reconciler.d.ts +2 -0
- package/dist/host-reconciler.d.ts.map +1 -1
- package/dist/host-reconciler.js +696 -55
- package/dist/host-reconciler.js.map +1 -1
- package/dist/jsx-dev-runtime.d.ts +3 -1
- package/dist/jsx-dev-runtime.d.ts.map +1 -1
- package/dist/jsx-dev-runtime.js +3 -1
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.d.ts +4 -2
- package/dist/jsx-runtime.d.ts.map +1 -1
- package/dist/jsx-runtime.js +9 -1
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/reactive-prop-cell.d.ts +13 -0
- package/dist/reactive-prop-cell.d.ts.map +1 -0
- package/dist/reactive-prop-cell.js +36 -0
- package/dist/reactive-prop-cell.js.map +1 -0
- package/dist/root.d.ts.map +1 -1
- package/dist/root.js +8 -5
- package/dist/root.js.map +1 -1
- package/package.json +3 -3
- package/src/devtools.ts +2 -0
- package/src/dom-host-rules.ts +4 -1
- package/src/dom-props.ts +2 -1
- package/src/element.ts +60 -3
- package/src/fiber-commit.ts +3 -1
- package/src/fiber-host.ts +2 -0
- package/src/fiber.ts +4 -0
- package/src/hooks.ts +187 -46
- package/src/host-reconciler.ts +1031 -70
- package/src/jsx-dev-runtime.ts +4 -0
- package/src/jsx-runtime.ts +16 -0
- package/src/reactive-prop-cell.ts +67 -0
- package/src/root.ts +14 -4
package/src/fiber.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type FiberTag =
|
|
|
15
15
|
| "memo"
|
|
16
16
|
| "lazy"
|
|
17
17
|
| "profiler"
|
|
18
|
+
| "reactive-dom-block"
|
|
18
19
|
| "strict-mode"
|
|
19
20
|
| "suspense"
|
|
20
21
|
| "suspense-list"
|
|
@@ -41,6 +42,7 @@ export interface Fiber {
|
|
|
41
42
|
childLanes: Lanes;
|
|
42
43
|
hydrateExisting: boolean;
|
|
43
44
|
hasRefSubtree: boolean;
|
|
45
|
+
hasDisposableResources: boolean;
|
|
44
46
|
hostChildListChanged: boolean;
|
|
45
47
|
}
|
|
46
48
|
|
|
@@ -96,6 +98,7 @@ export function createFiber(
|
|
|
96
98
|
childLanes: NoLanes,
|
|
97
99
|
hydrateExisting: false,
|
|
98
100
|
hasRefSubtree: false,
|
|
101
|
+
hasDisposableResources: false,
|
|
99
102
|
hostChildListChanged: false,
|
|
100
103
|
};
|
|
101
104
|
}
|
|
@@ -157,6 +160,7 @@ export function createWorkInProgress(
|
|
|
157
160
|
workInProgress.childLanes = current.childLanes;
|
|
158
161
|
workInProgress.hydrateExisting = false;
|
|
159
162
|
workInProgress.hasRefSubtree = current.hasRefSubtree;
|
|
163
|
+
workInProgress.hasDisposableResources = current.hasDisposableResources;
|
|
160
164
|
workInProgress.hostChildListChanged = current.hostChildListChanged;
|
|
161
165
|
return workInProgress;
|
|
162
166
|
}
|
package/src/hooks.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
flushPendingComputed,
|
|
3
3
|
flushQueuedComputations,
|
|
4
|
+
notifySubscribers,
|
|
5
|
+
trackSource,
|
|
6
|
+
type Source,
|
|
4
7
|
} from "@reckona/mreact-reactive-core/internal";
|
|
5
8
|
import { scheduleCallback } from "./fiber-scheduler.js";
|
|
6
9
|
import { removeChildIfPresent } from "./dom-children.js";
|
|
@@ -11,7 +14,10 @@ import {
|
|
|
11
14
|
useContext,
|
|
12
15
|
withContextReadObserver,
|
|
13
16
|
} from "./context.js";
|
|
14
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
REACTIVE_STATE_BINDING_META,
|
|
19
|
+
REACTIVE_TEXT_BINDING_META,
|
|
20
|
+
} from "./element.js";
|
|
15
21
|
import { isThenable } from "./thenable.js";
|
|
16
22
|
|
|
17
23
|
export interface RootRuntime {
|
|
@@ -127,7 +133,14 @@ export type DevToolsHookValue =
|
|
|
127
133
|
| { kind: "effect"; effectKind: "insertion" | "layout" | "normal"; deps?: readonly unknown[] };
|
|
128
134
|
|
|
129
135
|
type HookSlot =
|
|
130
|
-
| {
|
|
136
|
+
| {
|
|
137
|
+
kind: "state";
|
|
138
|
+
value: unknown;
|
|
139
|
+
dispatch?: (value: unknown) => void;
|
|
140
|
+
hostCommitValue?: unknown;
|
|
141
|
+
textBinding?: ReactiveTextBinding;
|
|
142
|
+
stateBinding?: ReactiveStateBinding;
|
|
143
|
+
}
|
|
131
144
|
| {
|
|
132
145
|
kind: "action-state";
|
|
133
146
|
state: unknown;
|
|
@@ -143,7 +156,13 @@ type HookSlot =
|
|
|
143
156
|
update: (state: unknown, payload: unknown) => unknown;
|
|
144
157
|
dispatch?: (payload: unknown) => void;
|
|
145
158
|
}
|
|
146
|
-
| {
|
|
159
|
+
| {
|
|
160
|
+
kind: "store";
|
|
161
|
+
value: unknown;
|
|
162
|
+
getSnapshot?: () => unknown;
|
|
163
|
+
hasMounted?: boolean;
|
|
164
|
+
hostCommitValue?: unknown;
|
|
165
|
+
}
|
|
147
166
|
| { kind: "ref"; value: { current: unknown } }
|
|
148
167
|
| { kind: "memo"; value: unknown; deps?: readonly unknown[] }
|
|
149
168
|
| { kind: "debug"; value: unknown }
|
|
@@ -158,9 +177,21 @@ type HookSlot =
|
|
|
158
177
|
strictReplay?: boolean;
|
|
159
178
|
};
|
|
160
179
|
|
|
180
|
+
interface PendingInstanceContext {
|
|
181
|
+
runtime: RootRuntime;
|
|
182
|
+
path: string;
|
|
183
|
+
owner: unknown;
|
|
184
|
+
existing: ComponentInstance | undefined;
|
|
185
|
+
}
|
|
186
|
+
|
|
161
187
|
interface HookRenderState {
|
|
162
188
|
currentRuntime: RootRuntime | undefined;
|
|
163
189
|
currentInstance: ComponentInstance | undefined;
|
|
190
|
+
// Deferred instance for the component currently rendering. The instance is
|
|
191
|
+
// only materialized (created, registered, prefix-indexed) when a hook or a
|
|
192
|
+
// context read first needs it, so components with no hooks/context (e.g. a
|
|
193
|
+
// pure host-rendering memo row) pay none of that per-render cost.
|
|
194
|
+
pendingInstance: PendingInstanceContext | undefined;
|
|
164
195
|
currentCacheScope: CacheScope | undefined;
|
|
165
196
|
hostCommitDepth: number;
|
|
166
197
|
queuedHostCommitRerenders: Set<RootRuntime>;
|
|
@@ -174,6 +205,7 @@ const hookRenderState =
|
|
|
174
205
|
] ??= {
|
|
175
206
|
currentRuntime: undefined,
|
|
176
207
|
currentInstance: undefined,
|
|
208
|
+
pendingInstance: undefined,
|
|
177
209
|
currentCacheScope: undefined,
|
|
178
210
|
hostCommitDepth: 0,
|
|
179
211
|
queuedHostCommitRerenders: new Set<RootRuntime>(),
|
|
@@ -204,6 +236,12 @@ export interface ReactiveTextBinding {
|
|
|
204
236
|
subscribers: Set<Text>;
|
|
205
237
|
}
|
|
206
238
|
|
|
239
|
+
export interface ReactiveStateBinding {
|
|
240
|
+
get(): unknown;
|
|
241
|
+
source: Source;
|
|
242
|
+
value: unknown;
|
|
243
|
+
}
|
|
244
|
+
|
|
207
245
|
const reactiveTextBindingsByNode = new WeakMap<Text, ReactiveTextBinding>();
|
|
208
246
|
const hydratedIdsByRuntime = new WeakMap<RootRuntime, Map<string, string>>();
|
|
209
247
|
|
|
@@ -378,6 +416,9 @@ export function createRootRuntime(
|
|
|
378
416
|
flushPendingEffects(this.pendingImperativeHandleEffects);
|
|
379
417
|
this.effectFlushPhase = "layout";
|
|
380
418
|
const strictLayoutEffects = flushPendingEffects(this.pendingLayoutEffects);
|
|
419
|
+
if (flushHostCommitRerenders()) {
|
|
420
|
+
dedupePendingEffects(this.pendingEffects);
|
|
421
|
+
}
|
|
381
422
|
this.effectFlushPhase = "normal";
|
|
382
423
|
const strictEffects = flushPendingEffects(this.pendingEffects);
|
|
383
424
|
this.effectFlushPhase = undefined;
|
|
@@ -502,25 +543,56 @@ export function renderWithRootRuntime<T>(
|
|
|
502
543
|
): T {
|
|
503
544
|
const previousRuntime = hookRenderState.currentRuntime;
|
|
504
545
|
const previousInstance = hookRenderState.currentInstance;
|
|
505
|
-
|
|
546
|
+
const previousPending = hookRenderState.pendingInstance;
|
|
506
547
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
548
|
+
let existing = runtime.instances.get(path);
|
|
549
|
+
if (existing !== undefined && owner !== undefined && existing.owner !== owner) {
|
|
550
|
+
cleanupInstance(existing);
|
|
551
|
+
runtime.instances.delete(path);
|
|
552
|
+
removeInstanceKeyFromIndex(runtime, path);
|
|
553
|
+
existing = undefined;
|
|
510
554
|
}
|
|
511
555
|
|
|
512
|
-
instance
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
556
|
+
// Defer instance materialization: hooks / context reads call
|
|
557
|
+
// materializeInstance() lazily. A component that touches neither never
|
|
558
|
+
// allocates or registers an instance.
|
|
559
|
+
hookRenderState.currentRuntime = runtime;
|
|
560
|
+
hookRenderState.currentInstance = undefined;
|
|
561
|
+
hookRenderState.pendingInstance = { runtime, path, owner, existing };
|
|
562
|
+
|
|
563
|
+
try {
|
|
564
|
+
return withContextReadObserver(recordContextDependency, render);
|
|
565
|
+
} finally {
|
|
566
|
+
hookRenderState.currentRuntime = previousRuntime;
|
|
567
|
+
hookRenderState.currentInstance = previousInstance;
|
|
568
|
+
hookRenderState.pendingInstance = previousPending;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// Materialize the deferred instance for the rendering component the first time
|
|
573
|
+
// a hook or context read needs it.
|
|
574
|
+
function materializeInstance(): ComponentInstance {
|
|
575
|
+
const pending = hookRenderState.pendingInstance;
|
|
576
|
+
if (pending === undefined) {
|
|
577
|
+
throw new Error("Hooks can only be called while rendering.");
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
const { runtime, path, owner } = pending;
|
|
581
|
+
let instance = pending.existing;
|
|
582
|
+
if (instance === undefined) {
|
|
583
|
+
instance = {
|
|
584
|
+
owner,
|
|
585
|
+
path,
|
|
586
|
+
hooks: [],
|
|
587
|
+
hookIndex: 0,
|
|
588
|
+
dirty: false,
|
|
589
|
+
devToolsHookSuppressionDepth: 0,
|
|
590
|
+
};
|
|
591
|
+
runtime.instances.set(path, instance);
|
|
592
|
+
indexInstanceKey(runtime, path);
|
|
593
|
+
} else {
|
|
594
|
+
instance.owner = owner;
|
|
595
|
+
}
|
|
524
596
|
runtime.activeInstanceKeys?.add(path);
|
|
525
597
|
instance.hookIndex = 0;
|
|
526
598
|
instance.dirty = false;
|
|
@@ -534,17 +606,17 @@ export function renderWithRootRuntime<T>(
|
|
|
534
606
|
delete instance.devToolsHookTypes;
|
|
535
607
|
}
|
|
536
608
|
instance.devToolsHookSuppressionDepth = 0;
|
|
537
|
-
hookRenderState.currentRuntime = runtime;
|
|
538
609
|
hookRenderState.currentInstance = instance;
|
|
610
|
+
hookRenderState.pendingInstance = undefined;
|
|
611
|
+
return instance;
|
|
612
|
+
}
|
|
539
613
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
hookRenderState.currentInstance = previousInstance;
|
|
547
|
-
}
|
|
614
|
+
function recordContextDependency(
|
|
615
|
+
context: ReactCompatContextLike<unknown>,
|
|
616
|
+
value: unknown,
|
|
617
|
+
): void {
|
|
618
|
+
const instance = hookRenderState.currentInstance ?? materializeInstance();
|
|
619
|
+
(instance.contextDependencies ??= new Map()).set(context, value);
|
|
548
620
|
}
|
|
549
621
|
|
|
550
622
|
export function hasChangedContextDependency(
|
|
@@ -575,22 +647,27 @@ export function hasContextDependency(
|
|
|
575
647
|
return keys.some((key) => runtime.instances.get(key)?.contextDependencies !== undefined);
|
|
576
648
|
}
|
|
577
649
|
|
|
650
|
+
// Shared read-only empty result so components with no registered instances
|
|
651
|
+
// (e.g. hookless rows under lazy instance materialization) don't each allocate
|
|
652
|
+
// a fresh array. Callers treat instance-key lists as read-only.
|
|
653
|
+
const EMPTY_INSTANCE_KEYS: string[] = [];
|
|
654
|
+
|
|
578
655
|
export function collectRuntimeInstanceKeys(runtime: RootRuntime, prefix: string): string[] {
|
|
579
656
|
const keys = runtime.instanceKeysByPrefix.get(prefix);
|
|
580
657
|
|
|
581
658
|
if (keys === undefined) {
|
|
582
|
-
return
|
|
659
|
+
return EMPTY_INSTANCE_KEYS;
|
|
583
660
|
}
|
|
584
661
|
|
|
585
|
-
|
|
662
|
+
let activeKeys: string[] | undefined;
|
|
586
663
|
|
|
587
664
|
for (const key of keys) {
|
|
588
665
|
if (runtime.instances.has(key)) {
|
|
589
|
-
activeKeys.push(key);
|
|
666
|
+
(activeKeys ??= []).push(key);
|
|
590
667
|
}
|
|
591
668
|
}
|
|
592
669
|
|
|
593
|
-
return activeKeys;
|
|
670
|
+
return activeKeys ?? EMPTY_INSTANCE_KEYS;
|
|
594
671
|
}
|
|
595
672
|
|
|
596
673
|
export function getDevToolsHookState(
|
|
@@ -787,11 +864,11 @@ export function useState<T>(
|
|
|
787
864
|
throw new Error("Hook order changed between renders.");
|
|
788
865
|
}
|
|
789
866
|
|
|
790
|
-
|
|
867
|
+
slot.dispatch ??= (value: unknown): void => {
|
|
791
868
|
const previousValue = slot.value;
|
|
792
869
|
const nextValue =
|
|
793
870
|
typeof value === "function"
|
|
794
|
-
? (value as (previous:
|
|
871
|
+
? (value as (previous: unknown) => unknown)(slot.value)
|
|
795
872
|
: value;
|
|
796
873
|
|
|
797
874
|
if (Object.is(slot.value, nextValue)) {
|
|
@@ -813,7 +890,17 @@ export function useState<T>(
|
|
|
813
890
|
optionsAllowDirectTextBinding(value) &&
|
|
814
891
|
updateDirectTextBinding(slot.textBinding, nextValue);
|
|
815
892
|
|
|
816
|
-
|
|
893
|
+
const canUseDirectStateBinding =
|
|
894
|
+
hookRenderState.hostCommitDepth === 0 &&
|
|
895
|
+
hookRenderState.currentRuntime !== runtime &&
|
|
896
|
+
hookRenderState.currentInstance !== instance &&
|
|
897
|
+
runtime.effectFlushPhase === undefined &&
|
|
898
|
+
eventBatchDepth === 0 &&
|
|
899
|
+
transitionDepth === 0 &&
|
|
900
|
+
optionsAllowDirectTextBinding(value) &&
|
|
901
|
+
updateDirectStateBinding(slot.stateBinding, nextValue);
|
|
902
|
+
|
|
903
|
+
if (canUseDirectTextBinding || canUseDirectStateBinding) {
|
|
817
904
|
return;
|
|
818
905
|
}
|
|
819
906
|
|
|
@@ -825,6 +912,7 @@ export function useState<T>(
|
|
|
825
912
|
|
|
826
913
|
scheduleInstanceUpdate(runtime, instance, { deferSync: typeof value === "function" });
|
|
827
914
|
};
|
|
915
|
+
const setState = slot.dispatch as (value: T | ((previous: T) => T)) => void;
|
|
828
916
|
|
|
829
917
|
recordDevToolsHook("useState", {
|
|
830
918
|
kind: "state",
|
|
@@ -836,6 +924,7 @@ export function useState<T>(
|
|
|
836
924
|
(value: T | ((previous: T) => T)) => void,
|
|
837
925
|
] & Record<PropertyKey, unknown>;
|
|
838
926
|
result[REACTIVE_TEXT_BINDING_META] = getStateTextBinding(slot);
|
|
927
|
+
result[REACTIVE_STATE_BINDING_META] = getStateBinding(slot);
|
|
839
928
|
return result;
|
|
840
929
|
}
|
|
841
930
|
|
|
@@ -884,6 +973,19 @@ function getStateTextBinding(slot: Extract<HookSlot, { kind: "state" }>): Reacti
|
|
|
884
973
|
return slot.textBinding;
|
|
885
974
|
}
|
|
886
975
|
|
|
976
|
+
function getStateBinding(slot: Extract<HookSlot, { kind: "state" }>): ReactiveStateBinding {
|
|
977
|
+
slot.stateBinding ??= {
|
|
978
|
+
value: slot.value,
|
|
979
|
+
source: { subscribers: null },
|
|
980
|
+
get() {
|
|
981
|
+
trackSource(this.source);
|
|
982
|
+
return this.value;
|
|
983
|
+
},
|
|
984
|
+
};
|
|
985
|
+
slot.stateBinding.value = slot.value;
|
|
986
|
+
return slot.stateBinding;
|
|
987
|
+
}
|
|
988
|
+
|
|
887
989
|
function optionsAllowDirectTextBinding(value: unknown): boolean {
|
|
888
990
|
return typeof value !== "function";
|
|
889
991
|
}
|
|
@@ -913,6 +1015,20 @@ function updateDirectTextBinding(binding: ReactiveTextBinding | undefined, value
|
|
|
913
1015
|
return updated;
|
|
914
1016
|
}
|
|
915
1017
|
|
|
1018
|
+
function updateDirectStateBinding(
|
|
1019
|
+
binding: ReactiveStateBinding | undefined,
|
|
1020
|
+
value: unknown,
|
|
1021
|
+
): boolean {
|
|
1022
|
+
if (binding === undefined || binding.source.subscribers === null) {
|
|
1023
|
+
return false;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
binding.value = value;
|
|
1027
|
+
notifySubscribers(binding.source);
|
|
1028
|
+
flushQueuedComputations();
|
|
1029
|
+
return true;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
916
1032
|
function isReactiveTextBinding(value: unknown): value is ReactiveTextBinding {
|
|
917
1033
|
return (
|
|
918
1034
|
typeof value === "object" &&
|
|
@@ -928,11 +1044,12 @@ export function useReducer<TState, TAction, TInitial = TState>(
|
|
|
928
1044
|
initialArg: TInitial,
|
|
929
1045
|
init?: (initialArg: TInitial) => TState,
|
|
930
1046
|
): [TState, (action: TAction) => void] {
|
|
931
|
-
const
|
|
1047
|
+
const stateTuple = runWithoutDevToolsHookTracking(() =>
|
|
932
1048
|
useState<TState>(() =>
|
|
933
1049
|
init === undefined ? (initialArg as unknown as TState) : init(initialArg),
|
|
934
1050
|
),
|
|
935
1051
|
);
|
|
1052
|
+
const [state, setState] = stateTuple;
|
|
936
1053
|
const reducerRef = runWithoutDevToolsHookTracking(() => useRef(reducer));
|
|
937
1054
|
const stateRef = runWithoutDevToolsHookTracking(() => useRef(state));
|
|
938
1055
|
const dispatchRef = runWithoutDevToolsHookTracking(() =>
|
|
@@ -956,7 +1073,18 @@ export function useReducer<TState, TAction, TInitial = TState>(
|
|
|
956
1073
|
value: state,
|
|
957
1074
|
});
|
|
958
1075
|
|
|
959
|
-
|
|
1076
|
+
const result = [state, dispatchRef.current] as [
|
|
1077
|
+
TState,
|
|
1078
|
+
(action: TAction) => void,
|
|
1079
|
+
] & Record<PropertyKey, unknown>;
|
|
1080
|
+
const stateBinding = (stateTuple as unknown as Record<PropertyKey, unknown>)[
|
|
1081
|
+
REACTIVE_STATE_BINDING_META
|
|
1082
|
+
];
|
|
1083
|
+
|
|
1084
|
+
if (stateBinding !== undefined) {
|
|
1085
|
+
result[REACTIVE_STATE_BINDING_META] = stateBinding;
|
|
1086
|
+
}
|
|
1087
|
+
return result;
|
|
960
1088
|
}
|
|
961
1089
|
|
|
962
1090
|
/** Returns a stable mutable ref object for the component instance. */
|
|
@@ -1300,6 +1428,7 @@ export function useSyncExternalStore<T>(
|
|
|
1300
1428
|
if (slot.kind !== "store") {
|
|
1301
1429
|
throw new Error("Hook order changed between renders.");
|
|
1302
1430
|
}
|
|
1431
|
+
slot.getSnapshot = getSnapshot as () => unknown;
|
|
1303
1432
|
|
|
1304
1433
|
const isHydrationMount =
|
|
1305
1434
|
runtime.idMode === "server" && slot.hasMounted !== true && getServerSnapshot !== undefined;
|
|
@@ -1319,7 +1448,7 @@ export function useSyncExternalStore<T>(
|
|
|
1319
1448
|
return;
|
|
1320
1449
|
}
|
|
1321
1450
|
|
|
1322
|
-
const nextSnapshot = getSnapshot();
|
|
1451
|
+
const nextSnapshot = (slot.getSnapshot ?? getSnapshot)();
|
|
1323
1452
|
|
|
1324
1453
|
if (!Object.is(slot.value, nextSnapshot)) {
|
|
1325
1454
|
if (hookRenderState.hostCommitDepth > 0 && !Object.hasOwn(slot, "hostCommitValue")) {
|
|
@@ -1353,7 +1482,7 @@ export function useSyncExternalStore<T>(
|
|
|
1353
1482
|
return () => {
|
|
1354
1483
|
unsubscribe();
|
|
1355
1484
|
};
|
|
1356
|
-
}, [subscribe
|
|
1485
|
+
}, [subscribe]));
|
|
1357
1486
|
|
|
1358
1487
|
recordDevToolsHook("useSyncExternalStore", {
|
|
1359
1488
|
kind: "store",
|
|
@@ -2044,15 +2173,16 @@ function scheduleInstanceUpdate(
|
|
|
2044
2173
|
scheduleRuntimeRerender(runtime, options);
|
|
2045
2174
|
}
|
|
2046
2175
|
|
|
2047
|
-
function flushHostCommitRerenders():
|
|
2176
|
+
function flushHostCommitRerenders(): boolean {
|
|
2048
2177
|
if (
|
|
2049
2178
|
hostCommitRerenderDepth > 0 ||
|
|
2050
2179
|
hookRenderState.hostCommitDepth > 0 ||
|
|
2051
2180
|
hookRenderState.queuedHostCommitRerenders.size === 0
|
|
2052
2181
|
) {
|
|
2053
|
-
return;
|
|
2182
|
+
return false;
|
|
2054
2183
|
}
|
|
2055
2184
|
|
|
2185
|
+
let didRerender = false;
|
|
2056
2186
|
hostCommitRerenderDepth += 1;
|
|
2057
2187
|
try {
|
|
2058
2188
|
for (
|
|
@@ -2069,6 +2199,7 @@ function flushHostCommitRerenders(): void {
|
|
|
2069
2199
|
clearHostCommitStateBaselines(runtime);
|
|
2070
2200
|
|
|
2071
2201
|
if (hasDirtyInstance) {
|
|
2202
|
+
didRerender = true;
|
|
2072
2203
|
runtime.rerender("sync");
|
|
2073
2204
|
}
|
|
2074
2205
|
}
|
|
@@ -2077,6 +2208,20 @@ function flushHostCommitRerenders(): void {
|
|
|
2077
2208
|
} finally {
|
|
2078
2209
|
hostCommitRerenderDepth -= 1;
|
|
2079
2210
|
}
|
|
2211
|
+
return didRerender;
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
function dedupePendingEffects(queue: PendingEffect[]): void {
|
|
2215
|
+
if (queue.length < 2) {
|
|
2216
|
+
return;
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
const latestBySlot = new Map<Extract<HookSlot, { kind: "effect" }>, PendingEffect>();
|
|
2220
|
+
for (const effect of queue) {
|
|
2221
|
+
latestBySlot.set(effect.slot, effect);
|
|
2222
|
+
}
|
|
2223
|
+
queue.length = 0;
|
|
2224
|
+
queue.push(...latestBySlot.values());
|
|
2080
2225
|
}
|
|
2081
2226
|
|
|
2082
2227
|
function flushEffectFlushRerenders(): void {
|
|
@@ -2299,11 +2444,7 @@ function requireRuntime(): RootRuntime {
|
|
|
2299
2444
|
}
|
|
2300
2445
|
|
|
2301
2446
|
function requireInstance(): ComponentInstance {
|
|
2302
|
-
|
|
2303
|
-
throw new Error("Hooks can only be called while rendering.");
|
|
2304
|
-
}
|
|
2305
|
-
|
|
2306
|
-
return hookRenderState.currentInstance;
|
|
2447
|
+
return hookRenderState.currentInstance ?? materializeInstance();
|
|
2307
2448
|
}
|
|
2308
2449
|
|
|
2309
2450
|
function areHookInputsEqual(
|