@reckona/mreact-compat 0.0.168 → 0.0.170
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/dom-children.d.ts.map +1 -1
- package/dist/dom-children.js +53 -0
- package/dist/dom-children.js.map +1 -1
- package/dist/element.d.ts +19 -4
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +56 -19
- package/dist/element.js.map +1 -1
- package/dist/hooks.js +18 -11
- package/dist/hooks.js.map +1 -1
- package/dist/host-reconciler.d.ts.map +1 -1
- package/dist/host-reconciler.js +263 -31
- package/dist/host-reconciler.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/jsx-dev-runtime.d.ts +1 -1
- package/dist/jsx-dev-runtime.d.ts.map +1 -1
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.d.ts +2 -2
- package/dist/jsx-runtime.d.ts.map +1 -1
- package/dist/jsx-runtime.js.map +1 -1
- package/package.json +3 -3
- package/src/dom-children.ts +78 -0
- package/src/element.ts +109 -23
- package/src/hooks.ts +24 -11
- package/src/host-reconciler.ts +430 -42
- package/src/index.ts +1 -0
- package/src/jsx-dev-runtime.ts +1 -1
- package/src/jsx-runtime.ts +3 -3
package/dist/host-reconciler.js
CHANGED
|
@@ -172,6 +172,7 @@ function reconcileHostChild(parent, currentFirstChild, node, runtime, path, opti
|
|
|
172
172
|
}
|
|
173
173
|
const childCount = children === undefined ? 1 : children.length;
|
|
174
174
|
const hasKeyedChildren = children !== undefined && hasKeyedChild(children);
|
|
175
|
+
const canReuseCurrentFibersInList = !hasKeyedChildren || currentFirstChild === undefined;
|
|
175
176
|
let existingByKey;
|
|
176
177
|
let currentKeyed = currentFirstChild;
|
|
177
178
|
let currentUnkeyed = currentFirstChild;
|
|
@@ -179,46 +180,77 @@ function reconcileHostChild(parent, currentFirstChild, node, runtime, path, opti
|
|
|
179
180
|
let previous;
|
|
180
181
|
let consumed = 0;
|
|
181
182
|
let skipRemainingKeyedLookup = false;
|
|
182
|
-
|
|
183
|
+
let sequentialCurrentCursor = currentFirstChild;
|
|
184
|
+
let childListOrderChanged = false;
|
|
185
|
+
let usedCurrentChildren = currentFirstChild === undefined || hasKeyedChildren ? undefined : new Set();
|
|
186
|
+
const ensureUsedCurrentChildren = () => {
|
|
187
|
+
if (usedCurrentChildren === undefined) {
|
|
188
|
+
usedCurrentChildren = new Set();
|
|
189
|
+
let cursor = currentFirstChild;
|
|
190
|
+
while (cursor !== undefined && cursor !== sequentialCurrentCursor) {
|
|
191
|
+
usedCurrentChildren.add(cursor);
|
|
192
|
+
cursor = cursor.sibling;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return usedCurrentChildren;
|
|
196
|
+
};
|
|
183
197
|
for (let index = 0; index < childCount; index += 1) {
|
|
184
198
|
const child = children === undefined ? node : children[index];
|
|
185
199
|
const key = getNodeKey(child);
|
|
186
200
|
let matchedCurrent;
|
|
201
|
+
let canReuseMatchedCurrentFiber = canReuseCurrentFibersInList;
|
|
187
202
|
if (key === undefined) {
|
|
203
|
+
if (hasKeyedChildren && currentUnkeyed !== undefined) {
|
|
204
|
+
childListOrderChanged = true;
|
|
205
|
+
ensureUsedCurrentChildren();
|
|
206
|
+
}
|
|
188
207
|
matchedCurrent = currentUnkeyed;
|
|
189
208
|
}
|
|
190
209
|
else if (skipRemainingKeyedLookup) {
|
|
210
|
+
childListOrderChanged = true;
|
|
191
211
|
matchedCurrent = undefined;
|
|
192
212
|
}
|
|
193
213
|
else if (existingByKey !== undefined) {
|
|
214
|
+
childListOrderChanged = true;
|
|
194
215
|
matchedCurrent = existingByKey.get(key);
|
|
216
|
+
canReuseMatchedCurrentFiber = matchedCurrent === undefined;
|
|
195
217
|
}
|
|
196
218
|
else if (currentKeyed?.key === key) {
|
|
197
219
|
matchedCurrent = currentKeyed;
|
|
220
|
+
canReuseMatchedCurrentFiber = true;
|
|
198
221
|
currentKeyed = currentKeyed.sibling;
|
|
222
|
+
sequentialCurrentCursor = currentKeyed;
|
|
199
223
|
}
|
|
200
224
|
else if (children !== undefined &&
|
|
201
225
|
currentKeyed?.sibling?.key === key &&
|
|
202
226
|
canSkipSingleDeletedKeyedFiber(children, index, currentKeyed.sibling)) {
|
|
227
|
+
childListOrderChanged = true;
|
|
228
|
+
ensureUsedCurrentChildren();
|
|
203
229
|
matchedCurrent = currentKeyed.sibling;
|
|
230
|
+
canReuseMatchedCurrentFiber = false;
|
|
204
231
|
currentKeyed = currentKeyed.sibling.sibling;
|
|
205
232
|
}
|
|
206
233
|
else {
|
|
207
234
|
if (children !== undefined &&
|
|
208
235
|
hasKeyedChildren &&
|
|
209
236
|
canSkipRemainingKeyedLookup(currentKeyed, children, index)) {
|
|
237
|
+
childListOrderChanged = true;
|
|
210
238
|
skipRemainingKeyedLookup = true;
|
|
211
239
|
currentKeyed = undefined;
|
|
212
240
|
}
|
|
213
241
|
else if (hasKeyedChildren) {
|
|
242
|
+
childListOrderChanged = true;
|
|
243
|
+
ensureUsedCurrentChildren();
|
|
214
244
|
existingByKey = collectExistingKeyedFibers(currentKeyed);
|
|
215
245
|
matchedCurrent = existingByKey.get(key);
|
|
246
|
+
canReuseMatchedCurrentFiber = matchedCurrent === undefined;
|
|
216
247
|
}
|
|
217
248
|
}
|
|
218
|
-
const
|
|
249
|
+
const memoBailout = tryReuseDependencyFreeMemoBailout(matchedCurrent, child, runtime, options, canReuseMatchedCurrentFiber);
|
|
250
|
+
const previousNodes = memoBailout !== undefined || options.previousNodes === undefined
|
|
219
251
|
? undefined
|
|
220
252
|
: options.previousNodes.slice(consumed);
|
|
221
|
-
const result = createHostFiber(parent, matchedCurrent, child, key, runtime, getReconcileChildPath(path, child, index, options), previousNodes === undefined ? options : { ...options, previousNodes });
|
|
253
|
+
const result = memoBailout ?? createHostFiber(parent, matchedCurrent, child, key, runtime, getReconcileChildPath(path, child, index, options), previousNodes === undefined ? options : { ...options, previousNodes }, canReuseMatchedCurrentFiber);
|
|
222
254
|
const fiber = result.fiber;
|
|
223
255
|
if (fiber === undefined) {
|
|
224
256
|
if (matchedCurrent !== undefined) {
|
|
@@ -257,14 +289,21 @@ function reconcileHostChild(parent, currentFirstChild, node, runtime, path, opti
|
|
|
257
289
|
}
|
|
258
290
|
previous = fiber;
|
|
259
291
|
}
|
|
260
|
-
|
|
261
|
-
|
|
292
|
+
if (usedCurrentChildren === undefined && hasKeyedChildren && currentKeyed !== undefined) {
|
|
293
|
+
markOptimizedChildrenForDeletion(parent, currentKeyed);
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
markUnusedCurrentChildrenForDeletion(parent, currentFirstChild, usedCurrentChildren);
|
|
297
|
+
}
|
|
298
|
+
parent.childListChanged =
|
|
299
|
+
childListOrderChanged || childFiberListShapeChanged(currentFirstChild, first);
|
|
262
300
|
return { fiber: first, consumed };
|
|
263
301
|
}
|
|
264
302
|
function reconcileKeyedRowHostChildren(parent, currentFirstChild, children, options) {
|
|
265
303
|
if (children.length === 0 ||
|
|
266
304
|
currentFirstChild === undefined ||
|
|
267
305
|
options.previousNodes !== undefined ||
|
|
306
|
+
!isKeyedRowHostElementCandidate(children[0]) ||
|
|
268
307
|
!shouldUseDirectHostTextChild()) {
|
|
269
308
|
return undefined;
|
|
270
309
|
}
|
|
@@ -430,6 +469,12 @@ function createKeyedRowHostElementScratch() {
|
|
|
430
469
|
text: "",
|
|
431
470
|
};
|
|
432
471
|
}
|
|
472
|
+
function isKeyedRowHostElementCandidate(node) {
|
|
473
|
+
return (isReactCompatElement(node) &&
|
|
474
|
+
typeof node.type === "string" &&
|
|
475
|
+
node.key !== null &&
|
|
476
|
+
node.ref === null);
|
|
477
|
+
}
|
|
433
478
|
function readKeyedRowHostElement(node, row) {
|
|
434
479
|
if (!isReactCompatElement(node) ||
|
|
435
480
|
typeof node.type !== "string" ||
|
|
@@ -611,8 +656,8 @@ function markHostFiberEffects(fiber, current, node) {
|
|
|
611
656
|
fiber.flags |= Update;
|
|
612
657
|
}
|
|
613
658
|
}
|
|
614
|
-
function createHostFiber(parent, current, node, key, runtime, path, options = {}) {
|
|
615
|
-
const result = createHostFiberImpl(parent, current, node, key, runtime, path, options);
|
|
659
|
+
function createHostFiber(parent, current, node, key, runtime, path, options = {}, canReuseCurrentFiber = true) {
|
|
660
|
+
const result = createHostFiberImpl(parent, current, node, key, runtime, path, options, canReuseCurrentFiber);
|
|
616
661
|
if (result.fiber !== undefined) {
|
|
617
662
|
if (canFinalizeNewHostFiber(result.fiber, current, node, options)) {
|
|
618
663
|
result.fiber.flags |= Placement;
|
|
@@ -633,7 +678,7 @@ function canFinalizeNewHostFiber(fiber, current, node, options) {
|
|
|
633
678
|
node.ref === null &&
|
|
634
679
|
typeof node.type === "string");
|
|
635
680
|
}
|
|
636
|
-
function createHostFiberImpl(parent, current, node, key, runtime, path, options = {}) {
|
|
681
|
+
function createHostFiberImpl(parent, current, node, key, runtime, path, options = {}, canReuseCurrentFiber = true) {
|
|
637
682
|
if (node === null || node === undefined || typeof node === "boolean") {
|
|
638
683
|
return { fiber: undefined, consumed: 0 };
|
|
639
684
|
}
|
|
@@ -667,6 +712,10 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
667
712
|
fiber.child = childResult.fiber;
|
|
668
713
|
return { fiber, consumed: childResult.consumed };
|
|
669
714
|
}
|
|
715
|
+
const memoBailout = tryReuseMemoBailout(current, node, runtime, path, options, canReuseCurrentFiber);
|
|
716
|
+
if (memoBailout !== undefined) {
|
|
717
|
+
return memoBailout;
|
|
718
|
+
}
|
|
670
719
|
if (!isReactCompatElement(node)) {
|
|
671
720
|
if (isReactCompatPortal(node)) {
|
|
672
721
|
return createPortalFiber(parent, current, node, key, runtime, path, options);
|
|
@@ -774,7 +823,7 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
774
823
|
fiber.type = forwardRefType;
|
|
775
824
|
const rendered = renderWithRootRuntime(runtime, path, () => forwardRefType.render(node.props, node.ref), forwardRefType);
|
|
776
825
|
fiber.memoizedState = getDevToolsHookState(runtime, path);
|
|
777
|
-
const childOptions =
|
|
826
|
+
const childOptions = getHydrationChildOptions(options, forwardRefType.render);
|
|
778
827
|
const childResult = reconcileHostChild(fiber, current?.tag === "forward-ref" ? current.child : undefined, rendered, runtime, `${path}.forwardRef`, childOptions);
|
|
779
828
|
fiber.child = childResult.fiber;
|
|
780
829
|
return { fiber, consumed: childResult.consumed };
|
|
@@ -785,22 +834,29 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
785
834
|
}
|
|
786
835
|
const memoType = node.type;
|
|
787
836
|
const memoPath = `${path}.memo`;
|
|
788
|
-
const
|
|
789
|
-
|
|
837
|
+
const previousMemoFiber = current?.tag === "memo" && current.type === memoType ? current : undefined;
|
|
838
|
+
const previousMemoState = previousMemoFiber !== undefined
|
|
839
|
+
? previousMemoFiber.memoizedState
|
|
790
840
|
: undefined;
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
!hasUnflushedMountEffectInstance(runtime, previousMemoState.instanceKeys) &&
|
|
841
|
+
if (previousMemoFiber !== undefined &&
|
|
842
|
+
previousMemoState !== undefined &&
|
|
843
|
+
!(memoStateNeedsDirtyInstanceCheck(previousMemoState) &&
|
|
844
|
+
hasDirtyInstance(runtime, previousMemoState.instanceKeys, memoPath)) &&
|
|
845
|
+
!(memoStateNeedsEffectCheck(previousMemoState) &&
|
|
846
|
+
hasUnflushedMountEffectInstance(runtime, previousMemoState.instanceKeys)) &&
|
|
798
847
|
areMemoPropsEqual(memoType, previousMemoState.props, node.props)) {
|
|
799
|
-
|
|
800
|
-
fiber.child = getSkippedChild(
|
|
848
|
+
const fiber = getMemoBailoutFiber(runtime, previousMemoFiber, node.props, previousMemoState, canReuseCurrentFiber);
|
|
849
|
+
fiber.child = getSkippedChild(previousMemoFiber);
|
|
801
850
|
fiber.memoizedState = previousMemoState;
|
|
802
|
-
return {
|
|
851
|
+
return {
|
|
852
|
+
fiber,
|
|
853
|
+
consumed: options.previousNodes?.length ?? 0,
|
|
854
|
+
};
|
|
803
855
|
}
|
|
856
|
+
const fiber = previousMemoFiber !== undefined
|
|
857
|
+
? createWorkInProgress(previousMemoFiber, node.props)
|
|
858
|
+
: createFiber("memo", node.props, key);
|
|
859
|
+
fiber.type = memoType;
|
|
804
860
|
const renderedElement = {
|
|
805
861
|
...node,
|
|
806
862
|
type: memoType.type,
|
|
@@ -812,9 +868,14 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
812
868
|
fiber.child.sibling = undefined;
|
|
813
869
|
bubbleHostChild(fiber, fiber.child);
|
|
814
870
|
}
|
|
871
|
+
const instanceKeys = collectInstanceKeys(runtime, memoPath);
|
|
872
|
+
const hasClassDescendant = hasClassComponentDescendant(fiber.child);
|
|
815
873
|
fiber.memoizedState = {
|
|
816
|
-
props:
|
|
817
|
-
instanceKeys
|
|
874
|
+
props: node.props,
|
|
875
|
+
instanceKeys,
|
|
876
|
+
hasDirtyInstanceDependencies: hasDirtyInstanceDependencies(runtime, instanceKeys) || hasClassDescendant,
|
|
877
|
+
hasUnflushedEffectDependencies: hasUnflushedEffectDependencies(runtime, instanceKeys),
|
|
878
|
+
hasRetainedInstanceDependencies: hasRetainedInstanceDependencies(runtime, instanceKeys) || hasClassDescendant,
|
|
818
879
|
};
|
|
819
880
|
return { fiber, consumed: childResult.consumed };
|
|
820
881
|
}
|
|
@@ -891,7 +952,7 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
891
952
|
fiber.child = getSkippedChild(current);
|
|
892
953
|
return { fiber, consumed: options.previousNodes?.length ?? 0 };
|
|
893
954
|
}
|
|
894
|
-
const childOptions =
|
|
955
|
+
const childOptions = getHydrationChildOptions(options, classType);
|
|
895
956
|
try {
|
|
896
957
|
const childResult = reconcileHostChild(fiber, current?.tag === "class-component" ? current.child : undefined, rendered.node, runtime, `${path}.class`, childOptions);
|
|
897
958
|
fiber.child = childResult.fiber;
|
|
@@ -939,7 +1000,7 @@ function createHostFiberImpl(parent, current, node, key, runtime, path, options
|
|
|
939
1000
|
}
|
|
940
1001
|
const rendered = renderWithRootRuntime(runtime, path, () => node.type(node.props), node.type);
|
|
941
1002
|
fiber.memoizedState = getDevToolsHookState(runtime, path);
|
|
942
|
-
const childOptions =
|
|
1003
|
+
const childOptions = getHydrationChildOptions(options, node.type);
|
|
943
1004
|
const childResult = reconcileHostChild(fiber, current?.tag === "function-component" ? current.child : undefined, rendered, runtime, `${path}.0`, childOptions);
|
|
944
1005
|
fiber.child = childResult.fiber;
|
|
945
1006
|
const instanceKeys = collectInstanceKeys(runtime, path);
|
|
@@ -1323,13 +1384,27 @@ function collectCommittedHostNodes(fiber) {
|
|
|
1323
1384
|
}
|
|
1324
1385
|
return nodes;
|
|
1325
1386
|
}
|
|
1387
|
+
function hasCommittedHostNode(fiber) {
|
|
1388
|
+
if ((fiber.tag === "host-component" || fiber.tag === "host-text") &&
|
|
1389
|
+
fiber.stateNode instanceof Node) {
|
|
1390
|
+
return true;
|
|
1391
|
+
}
|
|
1392
|
+
let child = fiber.child;
|
|
1393
|
+
while (child !== undefined) {
|
|
1394
|
+
if (hasCommittedHostNode(child)) {
|
|
1395
|
+
return true;
|
|
1396
|
+
}
|
|
1397
|
+
child = child.sibling;
|
|
1398
|
+
}
|
|
1399
|
+
return false;
|
|
1400
|
+
}
|
|
1326
1401
|
function getSkippedChild(current) {
|
|
1327
1402
|
const child = current?.child;
|
|
1328
1403
|
const alternateChild = current?.alternate?.child;
|
|
1329
1404
|
if (child !== undefined &&
|
|
1330
1405
|
alternateChild !== undefined &&
|
|
1331
|
-
|
|
1332
|
-
|
|
1406
|
+
!hasCommittedHostNode(child) &&
|
|
1407
|
+
hasCommittedHostNode(alternateChild)) {
|
|
1333
1408
|
return alternateChild;
|
|
1334
1409
|
}
|
|
1335
1410
|
return child;
|
|
@@ -1923,6 +1998,59 @@ function hasPendingAsyncChild(fiber) {
|
|
|
1923
1998
|
}
|
|
1924
1999
|
return false;
|
|
1925
2000
|
}
|
|
2001
|
+
function tryReuseMemoBailout(current, node, runtime, path, options, canReuseCurrentFiber = true) {
|
|
2002
|
+
if (current?.tag !== "memo" ||
|
|
2003
|
+
runtime === undefined ||
|
|
2004
|
+
!isReactCompatElement(node) ||
|
|
2005
|
+
node.type !== current.type ||
|
|
2006
|
+
!isMemoType(node.type)) {
|
|
2007
|
+
return undefined;
|
|
2008
|
+
}
|
|
2009
|
+
const previousMemoState = current.memoizedState;
|
|
2010
|
+
const memoPath = `${path}.memo`;
|
|
2011
|
+
if (previousMemoState === undefined ||
|
|
2012
|
+
(memoStateNeedsDirtyInstanceCheck(previousMemoState) &&
|
|
2013
|
+
hasDirtyInstance(runtime, previousMemoState.instanceKeys, memoPath)) ||
|
|
2014
|
+
(memoStateNeedsEffectCheck(previousMemoState) &&
|
|
2015
|
+
hasUnflushedMountEffectInstance(runtime, previousMemoState.instanceKeys)) ||
|
|
2016
|
+
!areMemoPropsEqual(node.type, previousMemoState.props, node.props)) {
|
|
2017
|
+
return undefined;
|
|
2018
|
+
}
|
|
2019
|
+
const fiber = getMemoBailoutFiber(runtime, current, node.props, previousMemoState, canReuseCurrentFiber);
|
|
2020
|
+
fiber.type = node.type;
|
|
2021
|
+
fiber.child = getSkippedChild(current);
|
|
2022
|
+
fiber.memoizedState = previousMemoState;
|
|
2023
|
+
return {
|
|
2024
|
+
fiber,
|
|
2025
|
+
consumed: options.previousNodes?.length ?? 0,
|
|
2026
|
+
};
|
|
2027
|
+
}
|
|
2028
|
+
function tryReuseDependencyFreeMemoBailout(current, node, runtime, options, canReuseCurrentFiber) {
|
|
2029
|
+
if (options.previousNodes !== undefined ||
|
|
2030
|
+
current?.tag !== "memo" ||
|
|
2031
|
+
runtime === undefined ||
|
|
2032
|
+
!isReactCompatElement(node) ||
|
|
2033
|
+
node.type !== current.type ||
|
|
2034
|
+
!isMemoType(node.type)) {
|
|
2035
|
+
return undefined;
|
|
2036
|
+
}
|
|
2037
|
+
const previousMemoState = current.memoizedState;
|
|
2038
|
+
if (previousMemoState === undefined ||
|
|
2039
|
+
previousMemoState.hasDirtyInstanceDependencies !== false ||
|
|
2040
|
+
previousMemoState.hasUnflushedEffectDependencies !== false ||
|
|
2041
|
+
previousMemoState.hasRetainedInstanceDependencies !== false ||
|
|
2042
|
+
!areMemoPropsEqual(node.type, previousMemoState.props, node.props)) {
|
|
2043
|
+
return undefined;
|
|
2044
|
+
}
|
|
2045
|
+
const fiber = getMemoBailoutFiber(runtime, current, node.props, previousMemoState, canReuseCurrentFiber);
|
|
2046
|
+
fiber.type = node.type;
|
|
2047
|
+
fiber.child = getSkippedChild(current);
|
|
2048
|
+
fiber.memoizedState = previousMemoState;
|
|
2049
|
+
return {
|
|
2050
|
+
fiber,
|
|
2051
|
+
consumed: 0,
|
|
2052
|
+
};
|
|
2053
|
+
}
|
|
1926
2054
|
function isPendingLazyFiber(fiber) {
|
|
1927
2055
|
if (fiber.tag !== "lazy" || !isLazyType(fiber.type)) {
|
|
1928
2056
|
return false;
|
|
@@ -2082,6 +2210,11 @@ function getRootCommitPath(options) {
|
|
|
2082
2210
|
function joinCommitPath(path, segment) {
|
|
2083
2211
|
return path === SKIP_COMMIT_PATH ? "" : joinPath(path, segment);
|
|
2084
2212
|
}
|
|
2213
|
+
function getHydrationChildOptions(options, component) {
|
|
2214
|
+
return options.hydration === undefined
|
|
2215
|
+
? options
|
|
2216
|
+
: withHydrationComponentStack(options, getComponentName(component));
|
|
2217
|
+
}
|
|
2085
2218
|
function getComponentName(component) {
|
|
2086
2219
|
return component.name === "" ? "Anonymous" : component.name;
|
|
2087
2220
|
}
|
|
@@ -2111,6 +2244,94 @@ function markActiveInstanceKeys(runtime, keys) {
|
|
|
2111
2244
|
runtime.activeInstanceKeys?.add(key);
|
|
2112
2245
|
}
|
|
2113
2246
|
}
|
|
2247
|
+
function memoStateNeedsDirtyInstanceCheck(state) {
|
|
2248
|
+
return state.hasDirtyInstanceDependencies !== false;
|
|
2249
|
+
}
|
|
2250
|
+
function memoStateNeedsEffectCheck(state) {
|
|
2251
|
+
return state.hasUnflushedEffectDependencies !== false;
|
|
2252
|
+
}
|
|
2253
|
+
function memoStateNeedsActiveInstanceMark(state) {
|
|
2254
|
+
return state.hasRetainedInstanceDependencies !== false;
|
|
2255
|
+
}
|
|
2256
|
+
function getMemoBailoutFiber(runtime, current, pendingProps, state, canReuseCurrentFiber) {
|
|
2257
|
+
if (canReuseCurrentFiber && canReuseMemoBailoutFiber(current, state)) {
|
|
2258
|
+
current.pendingProps = pendingProps;
|
|
2259
|
+
current.flags = NoFlags;
|
|
2260
|
+
current.subtreeFlags = NoFlags;
|
|
2261
|
+
current.childListChanged = false;
|
|
2262
|
+
current.subtreeChildListChanged = false;
|
|
2263
|
+
current.hostChildListChanged = false;
|
|
2264
|
+
return current;
|
|
2265
|
+
}
|
|
2266
|
+
const fiber = createWorkInProgress(current, pendingProps);
|
|
2267
|
+
if (memoStateNeedsActiveInstanceMark(state)) {
|
|
2268
|
+
markActiveInstanceKeys(runtime, state.instanceKeys);
|
|
2269
|
+
}
|
|
2270
|
+
return fiber;
|
|
2271
|
+
}
|
|
2272
|
+
function canReuseMemoBailoutFiber(current, state) {
|
|
2273
|
+
return (state.hasRetainedInstanceDependencies === false &&
|
|
2274
|
+
current.hasRefSubtree !== true &&
|
|
2275
|
+
current.hydrateExisting !== true);
|
|
2276
|
+
}
|
|
2277
|
+
function hasDirtyInstanceDependencies(runtime, keys) {
|
|
2278
|
+
for (const key of keys) {
|
|
2279
|
+
const instance = runtime.instances.get(key);
|
|
2280
|
+
if (instance === undefined || instance.contextDependencies !== undefined) {
|
|
2281
|
+
return true;
|
|
2282
|
+
}
|
|
2283
|
+
if (instance.hooks?.some(isDirtyCapableHookSlot) === true) {
|
|
2284
|
+
return true;
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
return false;
|
|
2288
|
+
}
|
|
2289
|
+
function hasRetainedInstanceDependencies(runtime, keys) {
|
|
2290
|
+
for (const key of keys) {
|
|
2291
|
+
const instance = runtime.instances.get(key);
|
|
2292
|
+
if (instance === undefined || instance.contextDependencies !== undefined) {
|
|
2293
|
+
return true;
|
|
2294
|
+
}
|
|
2295
|
+
if (instance.hooks !== undefined && instance.hooks.length > 0) {
|
|
2296
|
+
return true;
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
return false;
|
|
2300
|
+
}
|
|
2301
|
+
function isDirtyCapableHookSlot(slot) {
|
|
2302
|
+
if (slot === undefined) {
|
|
2303
|
+
return false;
|
|
2304
|
+
}
|
|
2305
|
+
return (slot.kind !== "ref" &&
|
|
2306
|
+
slot.kind !== "memo" &&
|
|
2307
|
+
slot.kind !== "debug" &&
|
|
2308
|
+
slot.kind !== "effect");
|
|
2309
|
+
}
|
|
2310
|
+
function hasUnflushedEffectDependencies(runtime, keys) {
|
|
2311
|
+
for (const key of keys) {
|
|
2312
|
+
const instance = runtime.instances.get(key);
|
|
2313
|
+
if (instance === undefined) {
|
|
2314
|
+
return true;
|
|
2315
|
+
}
|
|
2316
|
+
if (instance.hooks?.some((slot) => slot?.kind === "effect") === true) {
|
|
2317
|
+
return true;
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
return false;
|
|
2321
|
+
}
|
|
2322
|
+
function hasClassComponentDescendant(fiber) {
|
|
2323
|
+
let cursor = fiber;
|
|
2324
|
+
while (cursor !== undefined) {
|
|
2325
|
+
if (cursor.tag === "class-component") {
|
|
2326
|
+
return true;
|
|
2327
|
+
}
|
|
2328
|
+
if (hasClassComponentDescendant(cursor.child)) {
|
|
2329
|
+
return true;
|
|
2330
|
+
}
|
|
2331
|
+
cursor = cursor.sibling;
|
|
2332
|
+
}
|
|
2333
|
+
return false;
|
|
2334
|
+
}
|
|
2114
2335
|
function hasDirtyInstance(runtime, keys, prefix) {
|
|
2115
2336
|
if (runtime === undefined) {
|
|
2116
2337
|
return false;
|
|
@@ -2118,16 +2339,27 @@ function hasDirtyInstance(runtime, keys, prefix) {
|
|
|
2118
2339
|
if (hasDirtyClassUpdate(runtime, keys, prefix)) {
|
|
2119
2340
|
return true;
|
|
2120
2341
|
}
|
|
2342
|
+
if (keys.length === 0) {
|
|
2343
|
+
return false;
|
|
2344
|
+
}
|
|
2121
2345
|
if (keys.some((key) => runtime.instances.get(key)?.dirty === true)) {
|
|
2122
2346
|
return true;
|
|
2123
2347
|
}
|
|
2124
2348
|
if (prefix === undefined) {
|
|
2125
2349
|
return false;
|
|
2126
2350
|
}
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2351
|
+
// Resolve dirty descendants through the prefix index instead of scanning
|
|
2352
|
+
// every runtime instance. The previous full-map scan made memo/function
|
|
2353
|
+
// bailout O(total instances) per node, i.e. O(n^2) for large keyed lists
|
|
2354
|
+
// (js-framework-benchmark update-every-10th / select). The index is the same
|
|
2355
|
+
// source of truth used by collectRuntimeInstanceKeys.
|
|
2356
|
+
const keysUnderPrefix = runtime.instanceKeysByPrefix.get(prefix);
|
|
2357
|
+
if (keysUnderPrefix !== undefined) {
|
|
2358
|
+
for (const key of keysUnderPrefix) {
|
|
2359
|
+
if (runtime.instances.get(key)?.dirty ===
|
|
2360
|
+
true) {
|
|
2361
|
+
return true;
|
|
2362
|
+
}
|
|
2131
2363
|
}
|
|
2132
2364
|
}
|
|
2133
2365
|
return false;
|