Skip to content

Commit 4d79306

Browse files
committed
Render children passed to "backwards" SuspenseList in reverse mount order (facebook#35021)
Stacked on facebook#35018. This mounts the children of SuspenseList backwards. Meaning the first child is mounted last in the DOM (and effect list). It's like calling reverse() on the children. This is meant to set us up for allowing AsyncIterable children where the unknown number of children streams in at the end (which is the beginning in a backwards SuspenseList). For consistency we do that with other children too. `unstable_legacy-backwards` still exists for the old mode but is meant to be deprecated. <img width="100" alt="image" src="https://github.com/user-attachments/assets/5c2a95d7-34c4-4a4e-b602-3646a834d779" /> DiffTrain build for [488d88b](facebook@488d88b)
1 parent 0ee722d commit 4d79306

37 files changed

+3969
-3394
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
408b38ef7304faf022d2a37110c57efce12c6bad
1+
488d88b018ee8fd1fac56cab22dfa8796ebce30b
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
408b38ef7304faf022d2a37110c57efce12c6bad
1+
488d88b018ee8fd1fac56cab22dfa8796ebce30b

compiled/facebook-www/React-dev.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1499,7 +1499,7 @@ __DEV__ &&
14991499
exports.useTransition = function () {
15001500
return resolveDispatcher().useTransition();
15011501
};
1502-
exports.version = "19.3.0-www-classic-408b38ef-20251023";
1502+
exports.version = "19.3.0-www-classic-488d88b0-20251031";
15031503
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
15041504
"function" ===
15051505
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-dev.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1499,7 +1499,7 @@ __DEV__ &&
14991499
exports.useTransition = function () {
15001500
return resolveDispatcher().useTransition();
15011501
};
1502-
exports.version = "19.3.0-www-modern-408b38ef-20251023";
1502+
exports.version = "19.3.0-www-modern-488d88b0-20251031";
15031503
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
15041504
"function" ===
15051505
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-prod.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,4 +606,4 @@ exports.useSyncExternalStore = function (
606606
exports.useTransition = function () {
607607
return ReactSharedInternals.H.useTransition();
608608
};
609-
exports.version = "19.3.0-www-classic-408b38ef-20251023";
609+
exports.version = "19.3.0-www-classic-488d88b0-20251031";

compiled/facebook-www/React-prod.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,4 +606,4 @@ exports.useSyncExternalStore = function (
606606
exports.useTransition = function () {
607607
return ReactSharedInternals.H.useTransition();
608608
};
609-
exports.version = "19.3.0-www-modern-408b38ef-20251023";
609+
exports.version = "19.3.0-www-modern-488d88b0-20251031";

compiled/facebook-www/React-profiling.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ exports.useSyncExternalStore = function (
610610
exports.useTransition = function () {
611611
return ReactSharedInternals.H.useTransition();
612612
};
613-
exports.version = "19.3.0-www-classic-408b38ef-20251023";
613+
exports.version = "19.3.0-www-classic-488d88b0-20251031";
614614
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
615615
"function" ===
616616
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-profiling.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ exports.useSyncExternalStore = function (
610610
exports.useTransition = function () {
611611
return ReactSharedInternals.H.useTransition();
612612
};
613-
exports.version = "19.3.0-www-modern-408b38ef-20251023";
613+
exports.version = "19.3.0-www-modern-488d88b0-20251031";
614614
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
615615
"function" ===
616616
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/ReactART-dev.classic.js

Lines changed: 98 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -5482,10 +5482,7 @@ __DEV__ &&
54825482
return node;
54835483
} else if (
54845484
19 === node.tag &&
5485-
("forwards" === node.memoizedProps.revealOrder ||
5486-
"backwards" === node.memoizedProps.revealOrder ||
5487-
"unstable_legacy-backwards" === node.memoizedProps.revealOrder ||
5488-
"together" === node.memoizedProps.revealOrder)
5485+
"independent" !== node.memoizedProps.revealOrder
54895486
) {
54905487
if (0 !== (node.flags & 128)) return node;
54915488
} else if (null !== node.child) {
@@ -9058,6 +9055,16 @@ __DEV__ &&
90589055
propagationRoot
90599056
);
90609057
}
9058+
function findLastContentRow(firstChild) {
9059+
for (var lastContentRow = null; null !== firstChild; ) {
9060+
var currentRow = firstChild.alternate;
9061+
null !== currentRow &&
9062+
null === findFirstSuspended(currentRow) &&
9063+
(lastContentRow = firstChild);
9064+
firstChild = firstChild.sibling;
9065+
}
9066+
return lastContentRow;
9067+
}
90619068
function initSuspenseListRenderState(
90629069
workInProgress,
90639070
isBackwards,
@@ -9085,6 +9092,15 @@ __DEV__ &&
90859092
(renderState.tailMode = tailMode),
90869093
(renderState.treeForkCount = treeForkCount));
90879094
}
9095+
function reverseChildren(fiber) {
9096+
var row = fiber.child;
9097+
for (fiber.child = null; null !== row; ) {
9098+
var nextRow = row.sibling;
9099+
row.sibling = fiber.child;
9100+
fiber.child = row;
9101+
row = nextRow;
9102+
}
9103+
}
90889104
function updateSuspenseListComponent(current, workInProgress, renderLanes) {
90899105
var nextProps = workInProgress.pendingProps,
90909106
revealOrder = nextProps.revealOrder,
@@ -9101,23 +9117,18 @@ __DEV__ &&
91019117
push(suspenseStackCursor, suspenseContext, workInProgress);
91029118
suspenseContext = null == revealOrder ? "null" : revealOrder;
91039119
if (
9120+
null != revealOrder &&
91049121
"forwards" !== revealOrder &&
9122+
"backwards" !== revealOrder &&
91059123
"unstable_legacy-backwards" !== revealOrder &&
91069124
"together" !== revealOrder &&
91079125
"independent" !== revealOrder &&
91089126
!didWarnAboutRevealOrder[suspenseContext]
91099127
)
91109128
if (
9111-
((didWarnAboutRevealOrder[suspenseContext] = !0), null == revealOrder)
9129+
((didWarnAboutRevealOrder[suspenseContext] = !0),
9130+
"string" === typeof revealOrder)
91129131
)
9113-
console.error(
9114-
'The default for the <SuspenseList revealOrder="..."> prop is changing. To be future compatible you must explictly specify either "independent" (the current default), "together", "forwards" or "legacy_unstable-backwards".'
9115-
);
9116-
else if ("backwards" === revealOrder)
9117-
console.error(
9118-
'The rendering order of <SuspenseList revealOrder="backwards"> is changing. To be future compatible you must specify revealOrder="legacy_unstable-backwards" instead.'
9119-
);
9120-
else if ("string" === typeof revealOrder)
91219132
switch (revealOrder.toLowerCase()) {
91229133
case "together":
91239134
case "forwards":
@@ -9149,36 +9160,28 @@ __DEV__ &&
91499160
revealOrder
91509161
);
91519162
suspenseContext = null == tailMode ? "null" : tailMode;
9152-
if (!didWarnAboutTailOptions[suspenseContext])
9153-
if (null == tailMode) {
9154-
if (
9155-
"forwards" === revealOrder ||
9156-
"backwards" === revealOrder ||
9157-
"unstable_legacy-backwards" === revealOrder
9158-
)
9159-
(didWarnAboutTailOptions[suspenseContext] = !0),
9160-
console.error(
9161-
'The default for the <SuspenseList tail="..."> prop is changing. To be future compatible you must explictly specify either "visible" (the current default), "collapsed" or "hidden".'
9162-
);
9163-
} else
9164-
"visible" !== tailMode &&
9165-
"collapsed" !== tailMode &&
9166-
"hidden" !== tailMode
9167-
? ((didWarnAboutTailOptions[suspenseContext] = !0),
9168-
console.error(
9169-
'"%s" is not a supported value for tail on <SuspenseList />. Did you mean "visible", "collapsed" or "hidden"?',
9170-
tailMode
9171-
))
9172-
: "forwards" !== revealOrder &&
9173-
"backwards" !== revealOrder &&
9174-
"unstable_legacy-backwards" !== revealOrder &&
9175-
((didWarnAboutTailOptions[suspenseContext] = !0),
9176-
console.error(
9177-
'<SuspenseList tail="%s" /> is only valid if revealOrder is "forwards" or "backwards". Did you mean to specify revealOrder="forwards"?',
9178-
tailMode
9179-
));
9163+
didWarnAboutTailOptions[suspenseContext] ||
9164+
null == tailMode ||
9165+
("visible" !== tailMode &&
9166+
"collapsed" !== tailMode &&
9167+
"hidden" !== tailMode
9168+
? ((didWarnAboutTailOptions[suspenseContext] = !0),
9169+
console.error(
9170+
'"%s" is not a supported value for tail on <SuspenseList />. Did you mean "visible", "collapsed" or "hidden"?',
9171+
tailMode
9172+
))
9173+
: null != revealOrder &&
9174+
"forwards" !== revealOrder &&
9175+
"backwards" !== revealOrder &&
9176+
"unstable_legacy-backwards" !== revealOrder &&
9177+
((didWarnAboutTailOptions[suspenseContext] = !0),
9178+
console.error(
9179+
'<SuspenseList tail="%s" /> is only valid if revealOrder is "forwards" (default) or "backwards". Did you mean to specify revealOrder="forwards"?',
9180+
tailMode
9181+
)));
91809182
a: if (
9181-
("forwards" === revealOrder ||
9183+
(null == revealOrder ||
9184+
"forwards" === revealOrder ||
91829185
"backwards" === revealOrder ||
91839186
"unstable_legacy-backwards" === revealOrder) &&
91849187
void 0 !== nextProps &&
@@ -9217,7 +9220,11 @@ __DEV__ &&
92179220
'A single row was passed to a <SuspenseList revealOrder="%s" />. This is not useful since it needs multiple rows. Did you mean to pass multiple children or an array?',
92189221
revealOrder
92199222
);
9220-
reconcileChildren(current, workInProgress, nextProps, renderLanes);
9223+
"backwards" === revealOrder && null !== current
9224+
? (reverseChildren(current),
9225+
reconcileChildren(current, workInProgress, nextProps, renderLanes),
9226+
reverseChildren(current))
9227+
: reconcileChildren(current, workInProgress, nextProps, renderLanes);
92219228
if (
92229229
!shouldForceFallback &&
92239230
null !== current &&
@@ -9244,30 +9251,23 @@ __DEV__ &&
92449251
current = current.sibling;
92459252
}
92469253
switch (revealOrder) {
9247-
case "forwards":
9248-
renderLanes = workInProgress.child;
9249-
for (revealOrder = null; null !== renderLanes; )
9250-
(current = renderLanes.alternate),
9251-
null !== current &&
9252-
null === findFirstSuspended(current) &&
9253-
(revealOrder = renderLanes),
9254-
(renderLanes = renderLanes.sibling);
9255-
renderLanes = revealOrder;
9254+
case "backwards":
9255+
renderLanes = findLastContentRow(workInProgress.child);
92569256
null === renderLanes
92579257
? ((revealOrder = workInProgress.child),
92589258
(workInProgress.child = null))
92599259
: ((revealOrder = renderLanes.sibling),
9260-
(renderLanes.sibling = null));
9260+
(renderLanes.sibling = null),
9261+
reverseChildren(workInProgress));
92619262
initSuspenseListRenderState(
92629263
workInProgress,
9263-
!1,
9264+
!0,
92649265
revealOrder,
9265-
renderLanes,
9266+
null,
92669267
tailMode,
92679268
0
92689269
);
92699270
break;
9270-
case "backwards":
92719271
case "unstable_legacy-backwards":
92729272
renderLanes = null;
92739273
revealOrder = workInProgress.child;
@@ -9301,8 +9301,24 @@ __DEV__ &&
93019301
0
93029302
);
93039303
break;
9304-
default:
9304+
case "independent":
93059305
workInProgress.memoizedState = null;
9306+
break;
9307+
default:
9308+
(renderLanes = findLastContentRow(workInProgress.child)),
9309+
null === renderLanes
9310+
? ((revealOrder = workInProgress.child),
9311+
(workInProgress.child = null))
9312+
: ((revealOrder = renderLanes.sibling),
9313+
(renderLanes.sibling = null)),
9314+
initSuspenseListRenderState(
9315+
workInProgress,
9316+
!1,
9317+
revealOrder,
9318+
renderLanes,
9319+
tailMode,
9320+
0
9321+
);
93069322
}
93079323
return workInProgress.child;
93089324
}
@@ -10232,26 +10248,31 @@ __DEV__ &&
1023210248
}
1023310249
function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) {
1023410250
switch (renderState.tailMode) {
10235-
case "hidden":
10236-
hasRenderedATailFallback = renderState.tail;
10237-
for (var lastTailNode = null; null !== hasRenderedATailFallback; )
10238-
null !== hasRenderedATailFallback.alternate &&
10239-
(lastTailNode = hasRenderedATailFallback),
10240-
(hasRenderedATailFallback = hasRenderedATailFallback.sibling);
10241-
null === lastTailNode
10242-
? (renderState.tail = null)
10243-
: (lastTailNode.sibling = null);
10251+
case "visible":
1024410252
break;
1024510253
case "collapsed":
10246-
lastTailNode = renderState.tail;
10247-
for (var _lastTailNode = null; null !== lastTailNode; )
10248-
null !== lastTailNode.alternate && (_lastTailNode = lastTailNode),
10249-
(lastTailNode = lastTailNode.sibling);
10250-
null === _lastTailNode
10254+
for (
10255+
var tailNode = renderState.tail, lastTailNode = null;
10256+
null !== tailNode;
10257+
10258+
)
10259+
null !== tailNode.alternate && (lastTailNode = tailNode),
10260+
(tailNode = tailNode.sibling);
10261+
null === lastTailNode
1025110262
? hasRenderedATailFallback || null === renderState.tail
1025210263
? (renderState.tail = null)
1025310264
: (renderState.tail.sibling = null)
10254-
: (_lastTailNode.sibling = null);
10265+
: (lastTailNode.sibling = null);
10266+
break;
10267+
default:
10268+
hasRenderedATailFallback = renderState.tail;
10269+
for (tailNode = null; null !== hasRenderedATailFallback; )
10270+
null !== hasRenderedATailFallback.alternate &&
10271+
(tailNode = hasRenderedATailFallback),
10272+
(hasRenderedATailFallback = hasRenderedATailFallback.sibling);
10273+
null === tailNode
10274+
? (renderState.tail = null)
10275+
: (tailNode.sibling = null);
1025510276
}
1025610277
}
1025710278
function bubbleProperties(completedWork) {
@@ -10657,7 +10678,8 @@ __DEV__ &&
1065710678
scheduleRetryEffect(workInProgress, current),
1065810679
cutOffTailIfNeeded(instance, !0),
1065910680
null === instance.tail &&
10660-
"hidden" === instance.tailMode &&
10681+
"collapsed" !== instance.tailMode &&
10682+
"visible" !== instance.tailMode &&
1066110683
!_cache.alternate)
1066210684
)
1066310685
return bubbleProperties(workInProgress), null;
@@ -20371,10 +20393,10 @@ __DEV__ &&
2037120393
(function () {
2037220394
var internals = {
2037320395
bundleType: 1,
20374-
version: "19.3.0-www-classic-408b38ef-20251023",
20396+
version: "19.3.0-www-classic-488d88b0-20251031",
2037520397
rendererPackageName: "react-art",
2037620398
currentDispatcherRef: ReactSharedInternals,
20377-
reconcilerVersion: "19.3.0-www-classic-408b38ef-20251023"
20399+
reconcilerVersion: "19.3.0-www-classic-488d88b0-20251031"
2037820400
};
2037920401
internals.overrideHookState = overrideHookState;
2038020402
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -20409,7 +20431,7 @@ __DEV__ &&
2040920431
exports.Shape = Shape;
2041020432
exports.Surface = Surface;
2041120433
exports.Text = Text;
20412-
exports.version = "19.3.0-www-classic-408b38ef-20251023";
20434+
exports.version = "19.3.0-www-classic-488d88b0-20251031";
2041320435
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
2041420436
"function" ===
2041520437
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)