Skip to content

Commit 57fd488

Browse files
committed
[Float][Fiber] Implement waitForCommitToBeReady for stylesheet resources (#26450)
Before a commit is finished if any new stylesheet resources are going to mount and we are capable of delaying the commit we will do the following 1. Wait for all preloads for newly created stylesheet resources to load 2. Once all preloads are finished we insert the stylesheet instances for these resources and wait for them all to load 3. Once all stylesheets have loaded we complete the commit In this PR I also removed the synchronous loadingstate tracking in the fizz runtime. It was not necessary to support the implementation on not used by the fizz runtime itself. It makes the inline script slightly smaller In this PR I also integrated ReactDOMFloatClient with ReactDOMHostConfig. It leads to better code factoring, something I already did on the server a while back. To make the diff a little easier to follow i make these changes in a single commit so you can look at the change after that commit if helpful There is a 500ms timeout which will finish the commit even if all suspended host instances have not finished loading yet At the moment error and load events are treated the same and we're really tracking whether the host instance is finished attempting to load. DiffTrain build for commit 73b6435.
1 parent 9ed746c commit 57fd488

File tree

13 files changed

+810
-210
lines changed

13 files changed

+810
-210
lines changed

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js

Lines changed: 114 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1834,20 +1834,31 @@ function lanesToEventPriority(lanes) {
18341834

18351835
// Renderers that don't support hydration
18361836
// can re-export everything from this module.
1837-
function shim() {
1837+
function shim$1() {
18381838
throw new Error(
18391839
"The current renderer does not support hydration. " +
18401840
"This error is likely caused by a bug in React. " +
18411841
"Please file an issue."
18421842
);
18431843
} // Hydration (when unsupported)
1844-
var isSuspenseInstancePending = shim;
1845-
var isSuspenseInstanceFallback = shim;
1846-
var getSuspenseInstanceFallbackErrorDetails = shim;
1847-
var registerSuspenseInstanceRetry = shim;
1848-
var clearSuspenseBoundary = shim;
1849-
var clearSuspenseBoundaryFromContainer = shim;
1850-
var errorHydratingContainer = shim;
1844+
var isSuspenseInstancePending = shim$1;
1845+
var isSuspenseInstanceFallback = shim$1;
1846+
var getSuspenseInstanceFallbackErrorDetails = shim$1;
1847+
var registerSuspenseInstanceRetry = shim$1;
1848+
var clearSuspenseBoundary = shim$1;
1849+
var clearSuspenseBoundaryFromContainer = shim$1;
1850+
var errorHydratingContainer = shim$1;
1851+
1852+
// Renderers that don't support hydration
1853+
// can re-export everything from this module.
1854+
function shim() {
1855+
throw new Error(
1856+
"The current renderer does not support Resources. " +
1857+
"This error is likely caused by a bug in React. " +
1858+
"Please file an issue."
1859+
);
1860+
} // Resources (when unsupported)
1861+
var suspendResource = shim;
18511862

18521863
var NO_CONTEXT = {};
18531864
var UPDATE_SIGNAL = {};
@@ -2012,6 +2023,9 @@ function unhideInstance(instance, props) {
20122023
function unhideTextInstance(textInstance, text) {
20132024
textInstance.isHidden = false;
20142025
}
2026+
function maySuspendCommit(type, props) {
2027+
return false;
2028+
}
20152029
function preloadInstance(type, props) {
20162030
// Return true to indicate it's already loaded
20172031
return true;
@@ -4296,6 +4310,13 @@ function trackUsedThenable(thenableState, thenable, index) {
42964310
}
42974311
}
42984312
}
4313+
function suspendCommit() {
4314+
// This extra indirection only exists so it can handle passing
4315+
// noopSuspenseyCommitThenable through to throwException.
4316+
// TODO: Factor the thenable check out of throwException
4317+
suspendedThenable = noopSuspenseyCommitThenable;
4318+
throw SuspenseyCommitException;
4319+
} // This is used to track the actual thenable that suspended so it can be
42994320
// passed to the rest of the Suspense implementation — which, for historical
43004321
// reasons, expects to receive a thenable.
43014322

@@ -14594,16 +14615,28 @@ function preloadInstanceAndSuspendIfNeeded(
1459414615
props,
1459514616
renderLanes
1459614617
) {
14597-
// Ask the renderer if this instance should suspend the commit.
14598-
{
14599-
// If this flag was set previously, we can remove it. The flag represents
14600-
// whether this particular set of props might ever need to suspend. The
14601-
// safest thing to do is for maySuspendCommit to always return true, but
14602-
// if the renderer is reasonably confident that the underlying resource
14603-
// won't be evicted, it can return false as a performance optimization.
14604-
workInProgress.flags &= ~SuspenseyCommit;
14605-
return;
14606-
} // Mark this fiber with a flag. We use this right before the commit phase to
14618+
workInProgress.flags |= SuspenseyCommit; // Check if we're rendering at a "non-urgent" priority. This is the same
14619+
// check that `useDeferredValue` does to determine whether it needs to
14620+
// defer. This is partly for gradual adoption purposes (i.e. shouldn't start
14621+
// suspending until you opt in with startTransition or Suspense) but it
14622+
// also happens to be the desired behavior for the concrete use cases we've
14623+
// thought of so far, like CSS loading, fonts, images, etc.
14624+
// TODO: We may decide to expose a way to force a fallback even during a
14625+
// sync update.
14626+
14627+
if (!includesOnlyNonUrgentLanes(renderLanes));
14628+
else {
14629+
// Preload the instance
14630+
var isReady = preloadInstance();
14631+
14632+
if (!isReady) {
14633+
if (shouldRemainOnPreviousScreen());
14634+
else {
14635+
// Trigger a fallback rather than block the render.
14636+
suspendCommit();
14637+
}
14638+
}
14639+
}
1460714640
}
1460814641

1460914642
function scheduleRetryEffect(workInProgress, retryQueue) {
@@ -15011,6 +15044,8 @@ function completeWork(current, workInProgress, renderLanes) {
1501115044
popHostContext(workInProgress);
1501215045
var _type = workInProgress.type;
1501315046

15047+
var _maySuspend = maySuspendCommit();
15048+
1501415049
if (current !== null && workInProgress.stateNode != null) {
1501515050
updateHostComponent(current, workInProgress, _type, newProps);
1501615051

@@ -15071,7 +15106,17 @@ function completeWork(current, workInProgress, renderLanes) {
1507115106
// will resume rendering as if the work-in-progress completed. So it must
1507215107
// fully complete.
1507315108

15074-
preloadInstanceAndSuspendIfNeeded(workInProgress);
15109+
if (_maySuspend) {
15110+
preloadInstanceAndSuspendIfNeeded(
15111+
workInProgress,
15112+
_type,
15113+
newProps,
15114+
renderLanes
15115+
);
15116+
} else {
15117+
workInProgress.flags &= ~SuspenseyCommit;
15118+
}
15119+
1507515120
return null;
1507615121
}
1507715122

@@ -18929,6 +18974,50 @@ function commitPassiveUnmountEffects(finishedWork) {
1892918974
commitPassiveUnmountOnFiber(finishedWork);
1893018975
resetCurrentFiber();
1893118976
}
18977+
function accumulateSuspenseyCommit(finishedWork) {
18978+
accumulateSuspenseyCommitOnFiber(finishedWork);
18979+
}
18980+
18981+
function recursivelyAccumulateSuspenseyCommit(parentFiber) {
18982+
if (parentFiber.subtreeFlags & SuspenseyCommit) {
18983+
var child = parentFiber.child;
18984+
18985+
while (child !== null) {
18986+
accumulateSuspenseyCommitOnFiber(child);
18987+
child = child.sibling;
18988+
}
18989+
}
18990+
}
18991+
18992+
function accumulateSuspenseyCommitOnFiber(fiber) {
18993+
switch (fiber.tag) {
18994+
case HostHoistable: {
18995+
recursivelyAccumulateSuspenseyCommit(fiber);
18996+
18997+
if (fiber.flags & SuspenseyCommit) {
18998+
if (fiber.memoizedState !== null) {
18999+
suspendResource();
19000+
}
19001+
}
19002+
19003+
break;
19004+
}
19005+
19006+
case HostComponent: {
19007+
recursivelyAccumulateSuspenseyCommit(fiber);
19008+
19009+
break;
19010+
}
19011+
19012+
case HostRoot:
19013+
case HostPortal:
19014+
// eslint-disable-next-line-no-fallthrough
19015+
19016+
default: {
19017+
recursivelyAccumulateSuspenseyCommit(fiber);
19018+
}
19019+
}
19020+
}
1893219021

1893319022
function detachAlternateSiblings(parentFiber) {
1893419023
// A fiber was deleted from this parent fiber, but it's still part of the
@@ -20259,6 +20348,11 @@ function commitRootWhenReady(
2025920348
lanes
2026020349
) {
2026120350
if (includesOnlyNonUrgentLanes(lanes)) {
20351+
// the suspensey resources. The renderer is responsible for accumulating
20352+
// all the load events. This all happens in a single synchronous
20353+
// transaction, so it track state in its own module scope.
20354+
20355+
accumulateSuspenseyCommit(finishedWork); // At the end, ask the renderer if it's ready to commit, or if we should
2026220356
// suspend. If it's not ready, it will return a callback to subscribe to
2026320357
// a ready event.
2026420358

@@ -23649,7 +23743,7 @@ function createFiberRoot(
2364923743
return root;
2365023744
}
2365123745

23652-
var ReactVersion = "18.3.0-next-175962c10-20230325";
23746+
var ReactVersion = "18.3.0-next-73b6435ca-20230324";
2365323747

2365423748
// Might add PROFILE later.
2365523749

0 commit comments

Comments
 (0)