Skip to content

Commit b0a8a3e

Browse files
authored
Mark root as already hydrated after committing (#16739)
* Mark root as already hydrated after committing * Remove current/child check for hydration and rely on the root flag instead
1 parent e04f425 commit b0a8a3e

File tree

4 files changed

+40
-9
lines changed

4 files changed

+40
-9
lines changed

packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,21 @@ describe('ReactDOMServerHydration', () => {
502502
expect(element.textContent).toBe('Hello world');
503503
});
504504

505+
it('does not re-enter hydration after committing the first one', () => {
506+
let finalHTML = ReactDOMServer.renderToString(<div />);
507+
let container = document.createElement('div');
508+
container.innerHTML = finalHTML;
509+
let root = ReactDOM.unstable_createRoot(container, {hydrate: true});
510+
root.render(<div />);
511+
Scheduler.unstable_flushAll();
512+
root.render(null);
513+
Scheduler.unstable_flushAll();
514+
// This should not reenter hydration state and therefore not trigger hydration
515+
// warnings.
516+
root.render(<div />);
517+
Scheduler.unstable_flushAll();
518+
});
519+
505520
it('does not invoke an event on a concurrent hydrating node until it commits', () => {
506521
function Sibling({text}) {
507522
Scheduler.unstable_yieldValue('Sibling');

packages/react-reconciler/src/ReactFiberBeginWork.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -937,14 +937,7 @@ function updateHostRoot(current, workInProgress, renderExpirationTime) {
937937
);
938938
}
939939
const root: FiberRoot = workInProgress.stateNode;
940-
if (
941-
// TODO: This is a bug because if we render null after having hydrating,
942-
// we'll reenter hydration state at the next update which will then
943-
// trigger hydration warnings.
944-
(current === null || current.child === null) &&
945-
root.hydrate &&
946-
enterHydrationState(workInProgress)
947-
) {
940+
if (root.hydrate && enterHydrationState(workInProgress)) {
948941
// If we don't have any current children this might be the first pass.
949942
// We always try to hydrate. If this isn't a hydration pass there won't
950943
// be any children to hydrate which is effectively the same thing as

packages/react-reconciler/src/ReactFiberCommitWork.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ import {
8181
getPublicInstance,
8282
supportsMutation,
8383
supportsPersistence,
84+
supportsHydration,
8485
commitMount,
8586
commitUpdate,
8687
resetTextContent,
@@ -1297,6 +1298,16 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
12971298
attachSuspenseRetryListeners(finishedWork);
12981299
return;
12991300
}
1301+
case HostRoot: {
1302+
const root: FiberRoot = finishedWork.stateNode;
1303+
if (supportsHydration) {
1304+
if (root.hydrate) {
1305+
// We've just hydrated. No need to hydrate again.
1306+
root.hydrate = false;
1307+
}
1308+
}
1309+
break;
1310+
}
13001311
}
13011312

13021313
commitContainer(finishedWork);
@@ -1366,6 +1377,13 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
13661377
return;
13671378
}
13681379
case HostRoot: {
1380+
const root: FiberRoot = finishedWork.stateNode;
1381+
if (supportsHydration) {
1382+
if (root.hydrate) {
1383+
// We've just hydrated. No need to hydrate again.
1384+
root.hydrate = false;
1385+
}
1386+
}
13691387
return;
13701388
}
13711389
case Profiler: {

packages/react-reconciler/src/ReactFiberCompleteWork.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,12 @@ function completeWork(
662662
if (current === null || current.child === null) {
663663
// If we hydrated, pop so that we can delete any remaining children
664664
// that weren't hydrated.
665-
popHydrationState(workInProgress);
665+
let wasHydrated = popHydrationState(workInProgress);
666+
if (wasHydrated) {
667+
// If we hydrated, then we'll need to schedule an update for
668+
// the commit side-effects on the root.
669+
markUpdate(workInProgress);
670+
}
666671
}
667672
updateHostContainer(workInProgress);
668673
break;

0 commit comments

Comments
 (0)