diff --git a/packages/react-reconciler/src/ReactFiber.js b/packages/react-reconciler/src/ReactFiber.js
index 7ab798ea22b..129300a7d39 100644
--- a/packages/react-reconciler/src/ReactFiber.js
+++ b/packages/react-reconciler/src/ReactFiber.js
@@ -443,6 +443,49 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
return workInProgress;
}
+// Resets the stateNode to a fresh object.
+// This is used for components which don't set their stateNode in completeWork.
+function resetWorkInProgressStateNode(workInProgress: Fiber): void {
+ switch (workInProgress.tag) {
+ case ViewTransitionComponent:
+ const viewTransitionState: ViewTransitionState = {
+ autoName: null,
+ paired: null,
+ clones: null,
+ ref: null,
+ };
+ workInProgress.stateNode = viewTransitionState;
+ break;
+ case Profiler:
+ if (enableProfilerTimer) {
+ workInProgress.stateNode = {
+ effectDuration: 0,
+ passiveEffectDuration: 0,
+ };
+ }
+ break;
+ case TracingMarkerComponent:
+ if (enableTransitionTracing) {
+ const tracingMarkerInstance: TracingMarkerInstance = {
+ tag: TransitionTracingMarker,
+ transitions: null,
+ pendingBoundaries: null,
+ aborts: null,
+ name: workInProgress.pendingProps.name,
+ };
+ workInProgress.stateNode = tracingMarkerInstance;
+ }
+ break;
+ case HostPortal:
+ case DehydratedFragment:
+ // These preserve their stateNode
+ break;
+ default: {
+ workInProgress.stateNode = null;
+ }
+ }
+}
+
// Used to reuse a Fiber for a second pass.
export function resetWorkInProgress(
workInProgress: Fiber,
@@ -476,7 +519,7 @@ export function resetWorkInProgress(
workInProgress.dependencies = null;
- workInProgress.stateNode = null;
+ resetWorkInProgressStateNode(workInProgress);
if (enableProfilerTimer) {
// Note: We don't reset the actualTime counts. It's useful to accumulate
diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js
index 4ea1a152637..5579e0ed631 100644
--- a/packages/react-reconciler/src/ReactFiberBeginWork.js
+++ b/packages/react-reconciler/src/ReactFiberBeginWork.js
@@ -46,7 +46,6 @@ import type {
import type {UpdateQueue} from './ReactFiberClassUpdateQueue';
import type {RootState} from './ReactFiberRoot';
import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent';
-import type {ViewTransitionState} from './ReactFiberViewTransitionComponent';
import {
markComponentRenderStarted,
@@ -3563,18 +3562,6 @@ function updateViewTransition(
workInProgress: Fiber,
renderLanes: Lanes,
) {
- if (workInProgress.stateNode === null) {
- // We previously reset the work-in-progress.
- // We need to create a new ViewTransitionState instance.
- const instance: ViewTransitionState = {
- autoName: null,
- paired: null,
- clones: null,
- ref: null,
- };
- workInProgress.stateNode = instance;
- }
-
const pendingProps: ViewTransitionProps = workInProgress.pendingProps;
if (pendingProps.name != null && pendingProps.name !== 'auto') {
// Explicitly named boundary. We track it so that we can pair it up with another explicit
diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js
index c7d4de1421e..d9aa2143bb2 100644
--- a/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js
@@ -3736,4 +3736,176 @@ describe('ReactSuspenseList', () => {
' in Foo (at **)',
]);
});
+
+ // @gate enableSuspenseList
+ it('displays all "together" with various wrapper types as direct children', async () => {
+ const A = createAsyncText('A');
+ const B = createAsyncText('B');
+ const C = createAsyncText('C');
+ const D = createAsyncText('D');
+ const E = createAsyncText('E');
+ const F = createAsyncText('F');
+ const G = createAsyncText('G');
+
+ const MemoSuspense = React.memo(function MemoSuspense({
+ fallback,
+ children,
+ }) {
+ return