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

Pass children to hydration root constructor

I already made this change for the concurrent root API in #23309. This does the same thing for the legacy API. Doesn't change any behavior, but I will use this in the next steps.

Andrew Clark committed Mar 4, 2022 at 16:50 UTC c8e4789e21f6cb031b92b3bd8a905244bfd808b2
11 files changed +99 -56
packages/react-art/src/ReactART.js
-1
@@ -69,7 +69,6 @@ class Surface extends React.Component {
69 this._mountNode = createContainer(
70 this._surface,
71 LegacyRoot,
72 - false,
72 null,
73 false,
74 false,
packages/react-dom/src/__tests__/ReactDOMRoot-test.js
+9
@@ -253,6 +253,15 @@ describe('ReactDOMRoot', () => {
253 );
254 });
255
256 + it('callback passed to legacy hydrate() API', () => {
257 + container.innerHTML = '<div>Hi</div>';
258 + ReactDOM.hydrate(<div>Hi</div>, container, () => {
259 + Scheduler.unstable_yieldValue('callback');
260 + });
261 + expect(container.textContent).toEqual('Hi');
262 + expect(Scheduler).toHaveYielded(['callback']);
263 + });
264 +
265 it('warns when unmounting with legacy API (no previous content)', () => {
266 const root = ReactDOMClient.createRoot(container);
267 root.render(<div>Hi</div>);
packages/react-dom/src/client/ReactDOMLegacy.js
+79 -40
@@ -27,6 +27,7 @@ import {
27
28 import {
29 createContainer,
30 + createHydrationContainer,
31 findHostInstanceWithNoPortals,
32 updateContainer,
33 flushSync,
@@ -109,34 +110,81 @@ function noopOnRecoverableError() {
110
111 function legacyCreateRootFromDOMContainer(
112 container: Container,
112 - forceHydrate: boolean,
113 + initialChildren: ReactNodeList,
114 + parentComponent: ?React$Component<any, any>,
115 + callback: ?Function,
116 + isHydrationContainer: boolean,
117 ): FiberRoot {
114 - // First clear any existing content.
115 - if (!forceHydrate) {
118 + if (isHydrationContainer) {
119 + if (typeof callback === 'function') {
120 + const originalCallback = callback;
121 + callback = function() {
122 + const instance = getPublicRootInstance(root);
123 + originalCallback.call(instance);
124 + };
125 + }
126 +
127 + const root = createHydrationContainer(
128 + initialChildren,
129 + callback,
130 + container,
131 + LegacyRoot,
132 + null, // hydrationCallbacks
133 + false, // isStrictMode
134 + false, // concurrentUpdatesByDefaultOverride,
135 + '', // identifierPrefix
136 + noopOnRecoverableError,
137 + // TODO(luna) Support hydration later
138 + null,
139 + );
140 + container._reactRootContainer = root;
141 + markContainerAsRoot(root.current, container);
142 +
143 + const rootContainerElement =
144 + container.nodeType === COMMENT_NODE ? container.parentNode : container;
145 + listenToAllSupportedEvents(rootContainerElement);
146 +
147 + flushSync();
148 + return root;
149 + } else {
150 + // First clear any existing content.
151 let rootSibling;
152 while ((rootSibling = container.lastChild)) {
153 container.removeChild(rootSibling);
154 }
120 - }
155
122 - const root = createContainer(
123 - container,
124 - LegacyRoot,
125 - forceHydrate,
126 - null, // hydrationCallbacks
127 - false, // isStrictMode
128 - false, // concurrentUpdatesByDefaultOverride,
129 - '', // identifierPrefix
130 - noopOnRecoverableError, // onRecoverableError
131 - null, // transitionCallbacks
132 - );
133 - markContainerAsRoot(root.current, container);
156 + if (typeof callback === 'function') {
157 + const originalCallback = callback;
158 + callback = function() {
159 + const instance = getPublicRootInstance(root);
160 + originalCallback.call(instance);
161 + };
162 + }
163 +
164 + const root = createContainer(
165 + container,
166 + LegacyRoot,
167 + null, // hydrationCallbacks
168 + false, // isStrictMode
169 + false, // concurrentUpdatesByDefaultOverride,
170 + '', // identifierPrefix
171 + noopOnRecoverableError, // onRecoverableError
172 + null, // transitionCallbacks
173 + );
174 + container._reactRootContainer = root;
175 + markContainerAsRoot(root.current, container);
176 +
177 + const rootContainerElement =
178 + container.nodeType === COMMENT_NODE ? container.parentNode : container;
179 + listenToAllSupportedEvents(rootContainerElement);
180
135 - const rootContainerElement =
136 - container.nodeType === COMMENT_NODE ? container.parentNode : container;
137 - listenToAllSupportedEvents(rootContainerElement);
181 + // Initial mount should not be batched.
182 + flushSync(() => {
183 + updateContainer(initialChildren, root, parentComponent, callback);
184 + });
185
139 - return root;
186 + return root;
187 + }
188 }
189
190 function warnOnInvalidCallback(callback: mixed, callerName: string): void {
@@ -164,39 +212,30 @@ function legacyRenderSubtreeIntoContainer(
212 warnOnInvalidCallback(callback === undefined ? null : callback, 'render');
213 }
214
167 - let root = container._reactRootContainer;
168 - let fiberRoot: FiberRoot;
169 - if (!root) {
215 + const maybeRoot = container._reactRootContainer;
216 + let root: FiberRoot;
217 + if (!maybeRoot) {
218 // Initial mount
171 - root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
219 + root = legacyCreateRootFromDOMContainer(
220 container,
221 + children,
222 + parentComponent,
223 + callback,
224 forceHydrate,
225 );
175 - fiberRoot = root;
176 - if (typeof callback === 'function') {
177 - const originalCallback = callback;
178 - callback = function() {
179 - const instance = getPublicRootInstance(fiberRoot);
180 - originalCallback.call(instance);
181 - };
182 - }
183 - // Initial mount should not be batched.
184 - flushSync(() => {
185 - updateContainer(children, fiberRoot, parentComponent, callback);
186 - });
226 } else {
188 - fiberRoot = root;
227 + root = maybeRoot;
228 if (typeof callback === 'function') {
229 const originalCallback = callback;
230 callback = function() {
192 - const instance = getPublicRootInstance(fiberRoot);
231 + const instance = getPublicRootInstance(root);
232 originalCallback.call(instance);
233 };
234 }
235 // Update
197 - updateContainer(children, fiberRoot, parentComponent, callback);
236 + updateContainer(children, root, parentComponent, callback);
237 }
199 - return getPublicRootInstance(fiberRoot);
238 + return getPublicRootInstance(root);
239 }
240
241 export function findDOMNode(
packages/react-dom/src/client/ReactDOMRoot.js
+1 -1
@@ -225,7 +225,6 @@ export function createRoot(
225 const root = createContainer(
226 container,
227 ConcurrentRoot,
228 - false,
228 null,
229 isStrictMode,
230 concurrentUpdatesByDefaultOverride,
@@ -302,6 +301,7 @@ export function hydrateRoot(
301
302 const root = createHydrationContainer(
303 initialChildren,
304 + null,
305 container,
306 ConcurrentRoot,
307 hydrationCallbacks,
packages/react-native-renderer/src/ReactFabric.js
-1
@@ -215,7 +215,6 @@ function render(
215 root = createContainer(
216 containerTag,
217 concurrentRoot ? ConcurrentRoot : LegacyRoot,
218 - false,
218 null,
219 false,
220 null,
packages/react-native-renderer/src/ReactNativeRenderer.js
-1
@@ -211,7 +211,6 @@ function render(
211 root = createContainer(
212 containerTag,
213 LegacyRoot,
214 - false,
214 null,
215 false,
216 null,
packages/react-noop-renderer/src/createReactNoop.js
-3
@@ -974,7 +974,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
974 root = NoopRenderer.createContainer(
975 container,
976 tag,
977 - false,
977 null,
978 null,
979 false,
@@ -996,7 +995,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
995 const fiberRoot = NoopRenderer.createContainer(
996 container,
997 ConcurrentRoot,
999 - false,
998 null,
999 null,
1000 false,
@@ -1029,7 +1027,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1027 const fiberRoot = NoopRenderer.createContainer(
1028 container,
1029 LegacyRoot,
1032 - false,
1030 null,
1031 null,
1032 false,
packages/react-reconciler/src/ReactFiberReconciler.new.js
+5 -3
@@ -245,9 +245,6 @@ function findHostInstanceWithWarning(
245 export function createContainer(
246 containerInfo: Container,
247 tag: RootTag,
248 - // TODO: We can remove hydration-specific stuff from createContainer once
249 - // we delete legacy mode. The new root API uses createHydrationContainer.
250 - hydrate: boolean,
248 hydrationCallbacks: null | SuspenseHydrationCallbacks,
249 isStrictMode: boolean,
250 concurrentUpdatesByDefaultOverride: null | boolean,
@@ -255,6 +252,7 @@ export function createContainer(
252 onRecoverableError: (error: mixed) => void,
253 transitionCallbacks: null | TransitionTracingCallbacks,
254 ): OpaqueRoot {
255 + const hydrate = false;
256 return createFiberRoot(
257 containerInfo,
258 tag,
@@ -270,6 +268,8 @@ export function createContainer(
268
269 export function createHydrationContainer(
270 initialChildren: ReactNodeList,
271 + // TODO: Remove `callback` when we delete legacy mode.
272 + callback: ?Function,
273 containerInfo: Container,
274 tag: RootTag,
275 hydrationCallbacks: null | SuspenseHydrationCallbacks,
@@ -305,6 +305,8 @@ export function createHydrationContainer(
305 // Caution: React DevTools currently depends on this property
306 // being called "element".
307 update.payload = {element: initialChildren};
308 + update.callback =
309 + callback !== undefined && callback !== null ? callback : null;
310 enqueueUpdate(current, update, lane);
311 scheduleInitialHydrationOnRoot(root, lane, eventTime);
312
packages/react-reconciler/src/ReactFiberReconciler.old.js
+5 -3
@@ -245,9 +245,6 @@ function findHostInstanceWithWarning(
245 export function createContainer(
246 containerInfo: Container,
247 tag: RootTag,
248 - // TODO: We can remove hydration-specific stuff from createContainer once
249 - // we delete legacy mode. The new root API uses createHydrationContainer.
250 - hydrate: boolean,
248 hydrationCallbacks: null | SuspenseHydrationCallbacks,
249 isStrictMode: boolean,
250 concurrentUpdatesByDefaultOverride: null | boolean,
@@ -255,6 +252,7 @@ export function createContainer(
252 onRecoverableError: (error: mixed) => void,
253 transitionCallbacks: null | TransitionTracingCallbacks,
254 ): OpaqueRoot {
255 + const hydrate = false;
256 return createFiberRoot(
257 containerInfo,
258 tag,
@@ -270,6 +268,8 @@ export function createContainer(
268
269 export function createHydrationContainer(
270 initialChildren: ReactNodeList,
271 + // TODO: Remove `callback` when we delete legacy mode.
272 + callback: ?Function,
273 containerInfo: Container,
274 tag: RootTag,
275 hydrationCallbacks: null | SuspenseHydrationCallbacks,
@@ -305,6 +305,8 @@ export function createHydrationContainer(
305 // Caution: React DevTools currently depends on this property
306 // being called "element".
307 update.payload = {element: initialChildren};
308 + update.callback =
309 + callback !== undefined && callback !== null ? callback : null;
310 enqueueUpdate(current, update, lane);
311 scheduleInitialHydrationOnRoot(root, lane, eventTime);
312
packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js
-2
@@ -72,7 +72,6 @@ describe('ReactFiberHostContext', () => {
72 const container = Renderer.createContainer(
73 /* root: */ null,
74 ConcurrentRoot,
75 - false,
75 null,
76 false,
77 '',
@@ -136,7 +135,6 @@ describe('ReactFiberHostContext', () => {
135 const container = Renderer.createContainer(
136 rootContext,
137 ConcurrentRoot,
139 - false,
138 null,
139 false,
140 '',
packages/react-test-renderer/src/ReactTestRenderer.js
-1
@@ -473,7 +473,6 @@ function create(element: React$Element<any>, options: TestRendererOptions) {
473 let root: FiberRoot | null = createContainer(
474 container,
475 isConcurrent ? ConcurrentRoot : LegacyRoot,
476 - false,
476 null,
477 isStrictMode,
478 concurrentUpdatesByDefault,