Skip to content

Commit ed2bcf9

Browse files
committed
[Fiber] Wait for suspensey image in the viewport before starting an animation (#34500)
Stacked on #34486. If we gave up on loading suspensey images for blocking the commit (e.g. due to #34481), we can still block the view transition from committing to allow an animation to include the image from the start. At this point we have more information about the layout so we can include only the images that are within viewport in the calculation which may end up with a different answer. This only applies when we attempt to run an animation (e.g. something mutated inside a `<ViewTransition>` in a Transition). We could attempt a `startViewTransition` if we gave up on the suspensey images just so that we could block it even if no animation would be running. However, this point the screen is frozen and you can no longer have sync updates interrupt so ideally we would have already blocked the commit from happening in the first place. The reason to have two points where we block is that ideally we leave the UI responsive while blocking, which blocking the commit does. In the simple case of all images or a single image being within the viewport, that's favorable. By combining the techniques we only end up freezing the screen in the special case that we had a lot of images added outside the viewport and started an animation with some image inside the viewport (which presumably is about to finish anyway). DiffTrain build for [348a4e2](348a4e2)
1 parent 02ca3f9 commit ed2bcf9

24 files changed

+541
-305
lines changed

compiled-rn/VERSION_NATIVE_FB

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
19.2.0-native-fb-ae22247d-20250915
1+
19.2.0-native-fb-348a4e2d-20250915

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-dom/cjs/ReactDOM-dev.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<23cc05fee84e9c81ab6a7406c14940e4>>
10+
* @generated SignedSource<<85edb701d437b9e38e5582f59019adfc>>
1111
*/
1212

1313
"use strict";
@@ -404,5 +404,5 @@ __DEV__ &&
404404
exports.useFormStatus = function () {
405405
return resolveDispatcher().useHostTransitionStatus();
406406
};
407-
exports.version = "19.2.0-native-fb-ae22247d-20250915";
407+
exports.version = "19.2.0-native-fb-348a4e2d-20250915";
408408
})();

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-dom/cjs/ReactDOM-prod.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<f1a85f07f5eb7f943a9570b9d401499f>>
10+
* @generated SignedSource<<fcb57ee67fb57c6baac07f90c632e66b>>
1111
*/
1212

1313
"use strict";
@@ -203,4 +203,4 @@ exports.useFormState = function (action, initialState, permalink) {
203203
exports.useFormStatus = function () {
204204
return ReactSharedInternals.H.useHostTransitionStatus();
205205
};
206-
exports.version = "19.2.0-native-fb-ae22247d-20250915";
206+
exports.version = "19.2.0-native-fb-348a4e2d-20250915";

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-dom/cjs/ReactDOM-profiling.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<f1a85f07f5eb7f943a9570b9d401499f>>
10+
* @generated SignedSource<<fcb57ee67fb57c6baac07f90c632e66b>>
1111
*/
1212

1313
"use strict";
@@ -203,4 +203,4 @@ exports.useFormState = function (action, initialState, permalink) {
203203
exports.useFormStatus = function () {
204204
return ReactSharedInternals.H.useHostTransitionStatus();
205205
};
206-
exports.version = "19.2.0-native-fb-ae22247d-20250915";
206+
exports.version = "19.2.0-native-fb-348a4e2d-20250915";

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react/react-dom/cjs/ReactDOMClient-dev.js

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<e3366cdf976d39d2536c708f8a0a9f81>>
10+
* @generated SignedSource<<b707421577dff390a7d6b7ce377f95bf>>
1111
*/
1212

1313
/*
@@ -16858,34 +16858,59 @@ __DEV__ &&
1685816858
}
1685916859
alreadyWarnedForDeepEquality = prevDeepEquality;
1686016860
}
16861-
function recursivelyAccumulateSuspenseyCommit(parentFiber) {
16861+
function recursivelyAccumulateSuspenseyCommit(
16862+
parentFiber,
16863+
committedLanes,
16864+
suspendedState
16865+
) {
1686216866
if (parentFiber.subtreeFlags & suspenseyCommitFlag)
1686316867
for (parentFiber = parentFiber.child; null !== parentFiber; )
16864-
accumulateSuspenseyCommitOnFiber(parentFiber),
16868+
accumulateSuspenseyCommitOnFiber(
16869+
parentFiber,
16870+
committedLanes,
16871+
suspendedState
16872+
),
1686516873
(parentFiber = parentFiber.sibling);
1686616874
}
16867-
function accumulateSuspenseyCommitOnFiber(fiber) {
16875+
function accumulateSuspenseyCommitOnFiber(
16876+
fiber,
16877+
committedLanes,
16878+
suspendedState
16879+
) {
1686816880
switch (fiber.tag) {
1686916881
case 26:
16870-
recursivelyAccumulateSuspenseyCommit(fiber);
16882+
recursivelyAccumulateSuspenseyCommit(
16883+
fiber,
16884+
committedLanes,
16885+
suspendedState
16886+
);
1687116887
fiber.flags & suspenseyCommitFlag &&
1687216888
null !== fiber.memoizedState &&
1687316889
suspendResource(
16890+
suspendedState,
1687416891
currentHoistableRoot,
1687516892
fiber.memoizedState,
1687616893
fiber.memoizedProps
1687716894
);
1687816895
break;
1687916896
case 5:
16880-
recursivelyAccumulateSuspenseyCommit(fiber);
16897+
recursivelyAccumulateSuspenseyCommit(
16898+
fiber,
16899+
committedLanes,
16900+
suspendedState
16901+
);
1688116902
break;
1688216903
case 3:
1688316904
case 4:
1688416905
var previousHoistableRoot = currentHoistableRoot;
1688516906
currentHoistableRoot = getHoistableRoot(
1688616907
fiber.stateNode.containerInfo
1688716908
);
16888-
recursivelyAccumulateSuspenseyCommit(fiber);
16909+
recursivelyAccumulateSuspenseyCommit(
16910+
fiber,
16911+
committedLanes,
16912+
suspendedState
16913+
);
1688916914
currentHoistableRoot = previousHoistableRoot;
1689016915
break;
1689116916
case 22:
@@ -16895,12 +16920,24 @@ __DEV__ &&
1689516920
null !== previousHoistableRoot.memoizedState
1689616921
? ((previousHoistableRoot = suspenseyCommitFlag),
1689716922
(suspenseyCommitFlag = 16777216),
16898-
recursivelyAccumulateSuspenseyCommit(fiber),
16923+
recursivelyAccumulateSuspenseyCommit(
16924+
fiber,
16925+
committedLanes,
16926+
suspendedState
16927+
),
1689916928
(suspenseyCommitFlag = previousHoistableRoot))
16900-
: recursivelyAccumulateSuspenseyCommit(fiber));
16929+
: recursivelyAccumulateSuspenseyCommit(
16930+
fiber,
16931+
committedLanes,
16932+
suspendedState
16933+
));
1690116934
break;
1690216935
default:
16903-
recursivelyAccumulateSuspenseyCommit(fiber);
16936+
recursivelyAccumulateSuspenseyCommit(
16937+
fiber,
16938+
committedLanes,
16939+
suspendedState
16940+
);
1690416941
}
1690516942
}
1690616943
function detachAlternateSiblings(parentFiber) {
@@ -17586,6 +17623,7 @@ __DEV__ &&
1758617623
workInProgressRootInterleavedUpdatedLanes,
1758717624
workInProgressSuspendedRetryLanes,
1758817625
startTime,
17626+
null,
1758917627
IMMEDIATE_COMMIT,
1759017628
renderStartTime,
1759117629
forceSync
@@ -17669,25 +17707,27 @@ __DEV__ &&
1766917707
completedRenderEndTime
1767017708
) {
1767117709
root.timeoutHandle = noTimeout;
17672-
var subtreeFlags = finishedWork.subtreeFlags;
17710+
var subtreeFlags = finishedWork.subtreeFlags,
17711+
suspendedState = null;
1767317712
if (subtreeFlags & 8192 || 16785408 === (subtreeFlags & 16785408))
1767417713
if (
1767517714
((suspendedState = {
1767617715
stylesheets: null,
1767717716
count: 0,
1767817717
imgCount: 0,
1767917718
imgBytes: 0,
17719+
suspenseyImages: [],
1768017720
waitingForImages: !0,
1768117721
unsuspend: noop$1
1768217722
}),
17683-
accumulateSuspenseyCommitOnFiber(finishedWork),
17723+
accumulateSuspenseyCommitOnFiber(finishedWork, lanes, suspendedState),
1768417724
(subtreeFlags =
1768517725
(lanes & 62914560) === lanes
1768617726
? globalMostRecentFallbackTime - now$1()
1768717727
: (lanes & 4194048) === lanes
1768817728
? globalMostRecentTransitionTime - now$1()
1768917729
: 0),
17690-
(subtreeFlags = waitForCommitToBeReady(subtreeFlags)),
17730+
(subtreeFlags = waitForCommitToBeReady(suspendedState, subtreeFlags)),
1769117731
null !== subtreeFlags)
1769217732
) {
1769317733
root.cancelPendingCommit = subtreeFlags(
@@ -17703,6 +17743,7 @@ __DEV__ &&
1770317743
updatedLanes,
1770417744
suspendedRetryLanes,
1770517745
exitStatus,
17746+
suspendedState,
1770617747
SUSPENDED_COMMIT,
1770717748
completedRenderStartTime,
1770817749
completedRenderEndTime
@@ -17727,6 +17768,7 @@ __DEV__ &&
1772717768
updatedLanes,
1772817769
suspendedRetryLanes,
1772917770
exitStatus,
17771+
suspendedState,
1773017772
suspendedCommitReason,
1773117773
completedRenderStartTime,
1773217774
completedRenderEndTime
@@ -18764,6 +18806,7 @@ __DEV__ &&
1876418806
updatedLanes,
1876518807
suspendedRetryLanes,
1876618808
exitStatus,
18809+
suspendedState,
1876718810
suspendedCommitReason,
1876818811
completedRenderStartTime,
1876918812
completedRenderEndTime
@@ -24639,12 +24682,7 @@ __DEV__ &&
2463924682
? !1
2464024683
: !0;
2464124684
}
24642-
function suspendResource(hoistableRoot, resource, props) {
24643-
if (null === suspendedState)
24644-
throw Error(
24645-
"Internal React Error: suspendedState null when it was expected to exists. Please report this as a React bug."
24646-
);
24647-
var state = suspendedState;
24685+
function suspendResource(state, hoistableRoot, resource, props) {
2464824686
if (
2464924687
"stylesheet" === resource.type &&
2465024688
("string" !== typeof props.media ||
@@ -24693,12 +24731,7 @@ __DEV__ &&
2469324731
hoistableRoot.addEventListener("error", resource));
2469424732
}
2469524733
}
24696-
function waitForCommitToBeReady(timeoutOffset) {
24697-
if (null === suspendedState)
24698-
throw Error(
24699-
"Internal React Error: suspendedState null when it was expected to exists. Please report this as a React bug."
24700-
);
24701-
var state = suspendedState;
24734+
function waitForCommitToBeReady(state, timeoutOffset) {
2470224735
state.stylesheets &&
2470324736
0 === state.count &&
2470424737
insertSuspendedStylesheets(state, state.stylesheets);
@@ -29561,7 +29594,6 @@ __DEV__ &&
2956129594
};
2956229595
var globalDocument = "undefined" === typeof document ? null : document,
2956329596
tagCaches = null,
29564-
suspendedState = null,
2956529597
SUSPENSEY_STYLESHEET_TIMEOUT = 6e4,
2956629598
SUSPENSEY_IMAGE_TIMEOUT = 800,
2956729599
SUSPENSEY_IMAGE_TIME_ESTIMATE = 500,
@@ -29731,11 +29763,11 @@ __DEV__ &&
2973129763
};
2973229764
(function () {
2973329765
var isomorphicReactPackageVersion = React.version;
29734-
if ("19.2.0-native-fb-ae22247d-20250915" !== isomorphicReactPackageVersion)
29766+
if ("19.2.0-native-fb-348a4e2d-20250915" !== isomorphicReactPackageVersion)
2973529767
throw Error(
2973629768
'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' +
2973729769
(isomorphicReactPackageVersion +
29738-
"\n - react-dom: 19.2.0-native-fb-ae22247d-20250915\nLearn more: https://react.dev/warnings/version-mismatch")
29770+
"\n - react-dom: 19.2.0-native-fb-348a4e2d-20250915\nLearn more: https://react.dev/warnings/version-mismatch")
2973929771
);
2974029772
})();
2974129773
("function" === typeof Map &&
@@ -29772,10 +29804,10 @@ __DEV__ &&
2977229804
!(function () {
2977329805
var internals = {
2977429806
bundleType: 1,
29775-
version: "19.2.0-native-fb-ae22247d-20250915",
29807+
version: "19.2.0-native-fb-348a4e2d-20250915",
2977629808
rendererPackageName: "react-dom",
2977729809
currentDispatcherRef: ReactSharedInternals,
29778-
reconcilerVersion: "19.2.0-native-fb-ae22247d-20250915"
29810+
reconcilerVersion: "19.2.0-native-fb-348a4e2d-20250915"
2977929811
};
2978029812
internals.overrideHookState = overrideHookState;
2978129813
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -29924,5 +29956,5 @@ __DEV__ &&
2992429956
listenToAllSupportedEvents(container);
2992529957
return new ReactDOMHydrationRoot(initialChildren);
2992629958
};
29927-
exports.version = "19.2.0-native-fb-ae22247d-20250915";
29959+
exports.version = "19.2.0-native-fb-348a4e2d-20250915";
2992829960
})();

0 commit comments

Comments
 (0)