@samitouri / QOS-React-2 / commits / b0a8a3e041

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

Sebastian Markbåge committed Sep 10, 2019 at 20:02 UTC b0a8a3e04139eecf3ad46266abdab65e5abe60c7
4 files changed +40 -9
packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js
+15
@@ -502,6 +502,21 @@ describe('ReactDOMServerHydration', () => {
502 expect(element.textContent).toBe('Hello world');
503 });
504
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 +
520 it('does not invoke an event on a concurrent hydrating node until it commits', () => {
521 function Sibling({text}) {
522 Scheduler.unstable_yieldValue('Sibling');
packages/react-reconciler/src/ReactFiberBeginWork.js
+1 -8
@@ -937,14 +937,7 @@ function updateHostRoot(current, workInProgress, renderExpirationTime) {
937 );
938 }
939 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)) {
941 // If we don't have any current children this might be the first pass.
942 // We always try to hydrate. If this isn't a hydration pass there won't
943 // be any children to hydrate which is effectively the same thing as
packages/react-reconciler/src/ReactFiberCommitWork.js
+18
@@ -81,6 +81,7 @@ import {
81 getPublicInstance,
82 supportsMutation,
83 supportsPersistence,
84 + supportsHydration,
85 commitMount,
86 commitUpdate,
87 resetTextContent,
@@ -1297,6 +1298,16 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1298 attachSuspenseRetryListeners(finishedWork);
1299 return;
1300 }
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 + }
1311 }
1312
1313 commitContainer(finishedWork);
@@ -1366,6 +1377,13 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1377 return;
1378 }
1379 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 + }
1387 return;
1388 }
1389 case Profiler: {
packages/react-reconciler/src/ReactFiberCompleteWork.js
+6 -1
@@ -662,7 +662,12 @@ function completeWork(
662 if (current === null || current.child === null) {
663 // If we hydrated, pop so that we can delete any remaining children
664 // 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 + }
671 }
672 updateHostContainer(workInProgress);
673 break;