mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 00:20:04 +01:00
Enable Suspensey Images inside <ViewTransition> subtrees (#32820)
Even if the `enableSuspenseyImages` flag is off. Started View Transitions already wait for Suspensey Fonts and this is another Suspensey feature that is even more important for View Transitions - even though we eventually want it all the time. So this uses `<ViewTransition>` as an early opt-in for that tree into Suspensey Images, which we can ship in a minor. If you're doing an update inside a ViewTransition then we're eligible to start a ViewTransition in any Transition that might suspend. Even if that doesn't end up animating after all, we still consider it Suspensey. We could try to suspend inside the startViewTransition but that's not how it would work with `enableSuspenseyImages` on and we can't do that for startGestureTransition. Even so we still need some opt-in to trigger the Suspense fallback even before we know whether we'll animate or not. So the simple solution is just that `<ViewTransition>` opts in the whole subtree into Suspensey Images in general. In this PR I disable `enableSuspenseyImages` in experimental so that we can instead test the path that only enables it inside `<ViewTransition>` tree since that's the path that would next graduate to a minor.
This commit is contained in:
parent
ea05b750a5
commit
8da36d0508
|
|
@ -107,6 +107,7 @@ import {
|
|||
disableCommentsAsDOMContainers,
|
||||
enableSuspenseyImages,
|
||||
enableSrcObject,
|
||||
enableViewTransition,
|
||||
} from 'shared/ReactFeatureFlags';
|
||||
import {
|
||||
HostComponent,
|
||||
|
|
@ -5112,7 +5113,7 @@ export function isHostHoistableType(
|
|||
}
|
||||
|
||||
export function maySuspendCommit(type: Type, props: Props): boolean {
|
||||
if (!enableSuspenseyImages) {
|
||||
if (!enableSuspenseyImages && !enableViewTransition) {
|
||||
return false;
|
||||
}
|
||||
// Suspensey images are the default, unless you opt-out of with either
|
||||
|
|
@ -5206,7 +5207,7 @@ export function suspendInstance(
|
|||
type: Type,
|
||||
props: Props,
|
||||
): void {
|
||||
if (!enableSuspenseyImages) {
|
||||
if (!enableSuspenseyImages && !enableViewTransition) {
|
||||
return;
|
||||
}
|
||||
if (suspendedState === null) {
|
||||
|
|
|
|||
7
packages/react-reconciler/src/ReactFiber.js
vendored
7
packages/react-reconciler/src/ReactFiber.js
vendored
|
|
@ -41,6 +41,7 @@ import {
|
|||
disableLegacyMode,
|
||||
enableObjectFiber,
|
||||
enableViewTransition,
|
||||
enableSuspenseyImages,
|
||||
} from 'shared/ReactFeatureFlags';
|
||||
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
|
||||
import {ConcurrentRoot} from './ReactRootTags';
|
||||
|
|
@ -89,6 +90,7 @@ import {
|
|||
StrictLegacyMode,
|
||||
StrictEffectsMode,
|
||||
NoStrictPassiveEffectsMode,
|
||||
SuspenseyImagesMode,
|
||||
} from './ReactTypeOfMode';
|
||||
import {
|
||||
REACT_FORWARD_REF_TYPE,
|
||||
|
|
@ -875,6 +877,11 @@ export function createFiberFromViewTransition(
|
|||
lanes: Lanes,
|
||||
key: null | string,
|
||||
): Fiber {
|
||||
if (!enableSuspenseyImages) {
|
||||
// Render a ViewTransition component opts into SuspenseyImages mode even
|
||||
// when the flag is off.
|
||||
mode |= SuspenseyImagesMode;
|
||||
}
|
||||
const fiber = createFiber(ViewTransitionComponent, pendingProps, key, mode);
|
||||
fiber.elementType = REACT_VIEW_TRANSITION_TYPE;
|
||||
fiber.lanes = lanes;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import {
|
|||
disableLegacyMode,
|
||||
enableSiblingPrerendering,
|
||||
enableViewTransition,
|
||||
enableSuspenseyImages,
|
||||
} from 'shared/ReactFeatureFlags';
|
||||
|
||||
import {now} from './Scheduler';
|
||||
|
|
@ -77,7 +78,12 @@ import {
|
|||
ViewTransitionComponent,
|
||||
ActivityComponent,
|
||||
} from './ReactWorkTags';
|
||||
import {NoMode, ConcurrentMode, ProfileMode} from './ReactTypeOfMode';
|
||||
import {
|
||||
NoMode,
|
||||
ConcurrentMode,
|
||||
ProfileMode,
|
||||
SuspenseyImagesMode,
|
||||
} from './ReactTypeOfMode';
|
||||
import {
|
||||
Placement,
|
||||
Update,
|
||||
|
|
@ -555,9 +561,11 @@ function preloadInstanceAndSuspendIfNeeded(
|
|||
renderLanes: Lanes,
|
||||
) {
|
||||
const maySuspend =
|
||||
oldProps === null
|
||||
(enableSuspenseyImages ||
|
||||
(workInProgress.mode & SuspenseyImagesMode) !== NoMode) &&
|
||||
(oldProps === null
|
||||
? maySuspendCommit(type, newProps)
|
||||
: maySuspendCommitOnUpdate(type, oldProps, newProps);
|
||||
: maySuspendCommitOnUpdate(type, oldProps, newProps));
|
||||
|
||||
if (!maySuspend) {
|
||||
// If this flag was set previously, we can remove it. The flag
|
||||
|
|
|
|||
|
|
@ -12,8 +12,11 @@ export type TypeOfMode = number;
|
|||
export const NoMode = /* */ 0b0000000;
|
||||
// TODO: Remove ConcurrentMode by reading from the root tag instead
|
||||
export const ConcurrentMode = /* */ 0b0000001;
|
||||
export const ProfileMode = /* */ 0b0000010;
|
||||
export const ProfileMode = /* */ 0b0000010;
|
||||
//export const DebugTracingMode = /* */ 0b0000100; // Removed
|
||||
export const StrictLegacyMode = /* */ 0b0001000;
|
||||
export const StrictEffectsMode = /* */ 0b0010000;
|
||||
export const NoStrictPassiveEffectsMode = /* */ 0b1000000;
|
||||
// Keep track of if we're in a SuspenseyImages eligible subtree.
|
||||
// TODO: Remove this when enableSuspenseyImages ship where it's always on.
|
||||
export const SuspenseyImagesMode = /* */ 0b0100000;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
);
|
||||
}
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('suspend commit during initial mount', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
await act(async () => {
|
||||
|
|
@ -70,6 +71,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
expect(root).toMatchRenderedOutput(<suspensey-thing src="A" />);
|
||||
});
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('suspend commit during update', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
await act(() => resolveSuspenseyThing('A'));
|
||||
|
|
@ -105,6 +107,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
expect(root).toMatchRenderedOutput(<suspensey-thing src="B" />);
|
||||
});
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('suspend commit during initial mount at the root', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
await act(async () => {
|
||||
|
|
@ -121,6 +124,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
expect(root).toMatchRenderedOutput(<suspensey-thing src="A" />);
|
||||
});
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('suspend commit during update at the root', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
await act(() => resolveSuspenseyThing('A'));
|
||||
|
|
@ -147,6 +151,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
expect(root).toMatchRenderedOutput(<suspensey-thing src="B" />);
|
||||
});
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('suspend commit during urgent initial mount', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
await act(async () => {
|
||||
|
|
@ -165,6 +170,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
expect(root).toMatchRenderedOutput(<suspensey-thing src="A" />);
|
||||
});
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('suspend commit during urgent update', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
await act(() => resolveSuspenseyThing('A'));
|
||||
|
|
@ -203,6 +209,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
expect(root).toMatchRenderedOutput(<suspensey-thing src="B" />);
|
||||
});
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('suspends commit during urgent initial mount at the root', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
await act(async () => {
|
||||
|
|
@ -217,6 +224,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
expect(root).toMatchRenderedOutput(<suspensey-thing src="A" />);
|
||||
});
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('suspends commit during urgent update at the root', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
await act(() => resolveSuspenseyThing('A'));
|
||||
|
|
@ -239,6 +247,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
expect(root).toMatchRenderedOutput(<suspensey-thing src="B" />);
|
||||
});
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('does suspend commit during urgent initial mount at the root when sync rendering', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
await act(async () => {
|
||||
|
|
@ -256,6 +265,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
expect(root).toMatchRenderedOutput(<suspensey-thing src="A" />);
|
||||
});
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('does suspend commit during urgent update at the root when sync rendering', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
await act(() => resolveSuspenseyThing('A'));
|
||||
|
|
@ -283,6 +293,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
expect(root).toMatchRenderedOutput(<suspensey-thing src="B" />);
|
||||
});
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('an urgent update interrupts a suspended commit', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
|
||||
|
|
@ -305,6 +316,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
expect(root).toMatchRenderedOutput('Something else');
|
||||
});
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('a transition update interrupts a suspended commit', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
|
||||
|
|
@ -329,7 +341,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
expect(root).toMatchRenderedOutput('Something else');
|
||||
});
|
||||
|
||||
// @gate enableSuspenseList
|
||||
// @gate enableSuspenseList && enableSuspenseyImages
|
||||
it('demonstrate current behavior when used with SuspenseList (not ideal)', async () => {
|
||||
function App() {
|
||||
return (
|
||||
|
|
@ -381,6 +393,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate enableSuspenseyImages
|
||||
it('avoid triggering a fallback if resource loads immediately', async () => {
|
||||
const root = ReactNoop.createRoot();
|
||||
await act(async () => {
|
||||
|
|
@ -429,7 +442,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
);
|
||||
});
|
||||
|
||||
// @gate enableActivity
|
||||
// @gate enableActivity && enableSuspenseyImages
|
||||
it("host instances don't suspend during prerendering, but do suspend when they are revealed", async () => {
|
||||
function More() {
|
||||
Scheduler.log('More');
|
||||
|
|
@ -493,7 +506,7 @@ describe('ReactSuspenseyCommitPhase', () => {
|
|||
});
|
||||
|
||||
// FIXME: Should pass with `enableYieldingBeforePassive`
|
||||
// @gate !enableYieldingBeforePassive
|
||||
// @gate !enableYieldingBeforePassive && enableSuspenseyImages
|
||||
it('runs passive effects after suspended commit resolves', async () => {
|
||||
function Effect() {
|
||||
React.useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ export const enableGestureTransition = __EXPERIMENTAL__;
|
|||
|
||||
export const enableScrollEndPolyfill = __EXPERIMENTAL__;
|
||||
|
||||
export const enableSuspenseyImages = __EXPERIMENTAL__;
|
||||
export const enableSuspenseyImages = false;
|
||||
|
||||
export const enableSrcObject = __EXPERIMENTAL__;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user