@samitouri / QOS-React / commits / 1c44437355

Fix createRoot container signature (#24110)

The internal Container type represents the types of containers that React can support in its internals that deal with containers. This didn't include DocumentFragment which we support specifically for rendering into shadow roots. However, not all types makes sense to pass into the createRoot API. One of those is comment nodes that is deprecated and we don't really fully support. It really only exists for FB legacy. For createRoot it doesn't make sense to pass a Document since that will try to empty the document which removes the HTML tag which doesn't work. Documents can only be passed to hydrateRoot. Conversely I'm not sure we actually support hydrating a shadow root properly so I excluded DocumentFragment from hydrateRoot.

Sebastian Markbåge committed Mar 16, 2022 at 20:06 UTC 1c44437355e21f2992344fdef9ab1c1c5a7f8c2b
5 files changed +24 -23
packages/react-dom/client.js
+2 -3
@@ -9,7 +9,6 @@
9
10 'use strict';
11
12 -import type {Container} from './src/client/ReactDOMHostConfig';
12 import type {ReactNodeList} from 'shared/ReactTypes';
13 import type {
14 RootType,
@@ -24,7 +23,7 @@ import {
23 } from './';
24
25 export function createRoot(
27 - container: Container,
26 + container: Element | DocumentFragment,
27 options?: CreateRootOptions,
28 ): RootType {
29 if (__DEV__) {
@@ -40,7 +39,7 @@ export function createRoot(
39 }
40
41 export function hydrateRoot(
43 - container: Container,
42 + container: Document | Element,
43 children: ReactNodeList,
44 options?: HydrateRootOptions,
45 ): RootType {
packages/react-dom/src/client/ReactDOM.js
+2 -2
@@ -148,7 +148,7 @@ const Internals = {
148 };
149
150 function createRoot(
151 - container: Container,
151 + container: Element | DocumentFragment,
152 options?: CreateRootOptions,
153 ): RootType {
154 if (__DEV__) {
@@ -163,7 +163,7 @@ function createRoot(
163 }
164
165 function hydrateRoot(
166 - container: Container,
166 + container: Document | Element,
167 initialChildren: ReactNodeList,
168 options?: HydrateRootOptions,
169 ): RootType {
packages/react-dom/src/client/ReactDOMComponent.js
+11 -11
@@ -259,7 +259,7 @@ export function checkForUnmatchedText(
259 }
260
261 function getOwnerDocumentFromRootContainer(
262 - rootContainerElement: Element | Document,
262 + rootContainerElement: Element | Document | DocumentFragment,
263 ): Document {
264 return rootContainerElement.nodeType === DOCUMENT_NODE
265 ? (rootContainerElement: any)
@@ -284,7 +284,7 @@ export function trapClickOnNonInteractiveElement(node: HTMLElement) {
284 function setInitialDOMProperties(
285 tag: string,
286 domElement: Element,
287 - rootContainerElement: Element | Document,
287 + rootContainerElement: Element | Document | DocumentFragment,
288 nextProps: Object,
289 isCustomComponentTag: boolean,
290 ): void {
@@ -371,7 +371,7 @@ function updateDOMProperties(
371 export function createElement(
372 type: string,
373 props: Object,
374 - rootContainerElement: Element | Document,
374 + rootContainerElement: Element | Document | DocumentFragment,
375 parentNamespace: string,
376 ): Element {
377 let isCustomComponentTag;
@@ -477,7 +477,7 @@ export function createElement(
477
478 export function createTextNode(
479 text: string,
480 - rootContainerElement: Element | Document,
480 + rootContainerElement: Element | Document | DocumentFragment,
481 ): Text {
482 return getOwnerDocumentFromRootContainer(rootContainerElement).createTextNode(
483 text,
@@ -488,7 +488,7 @@ export function setInitialProperties(
488 domElement: Element,
489 tag: string,
490 rawProps: Object,
491 - rootContainerElement: Element | Document,
491 + rootContainerElement: Element | Document | DocumentFragment,
492 ): void {
493 const isCustomComponentTag = isCustomComponent(tag, rawProps);
494 if (__DEV__) {
@@ -614,7 +614,7 @@ export function diffProperties(
614 tag: string,
615 lastRawProps: Object,
616 nextRawProps: Object,
617 - rootContainerElement: Element | Document,
617 + rootContainerElement: Element | Document | DocumentFragment,
618 ): null | Array<mixed> {
619 if (__DEV__) {
620 validatePropertiesInDevelopment(tag, nextRawProps);
@@ -867,7 +867,7 @@ export function diffHydratedProperties(
867 tag: string,
868 rawProps: Object,
869 parentNamespace: string,
870 - rootContainerElement: Element | Document,
870 + rootContainerElement: Element | Document | DocumentFragment,
871 isConcurrentMode: boolean,
872 shouldWarnDev: boolean,
873 ): null | Array<mixed> {
@@ -1200,7 +1200,7 @@ export function diffHydratedText(
1200 }
1201
1202 export function warnForDeletedHydratableElement(
1203 - parentNode: Element | Document,
1203 + parentNode: Element | Document | DocumentFragment,
1204 child: Element,
1205 ) {
1206 if (__DEV__) {
@@ -1217,7 +1217,7 @@ export function warnForDeletedHydratableElement(
1217 }
1218
1219 export function warnForDeletedHydratableText(
1220 - parentNode: Element | Document,
1220 + parentNode: Element | Document | DocumentFragment,
1221 child: Text,
1222 ) {
1223 if (__DEV__) {
@@ -1234,7 +1234,7 @@ export function warnForDeletedHydratableText(
1234 }
1235
1236 export function warnForInsertedHydratedElement(
1237 - parentNode: Element | Document,
1237 + parentNode: Element | Document | DocumentFragment,
1238 tag: string,
1239 props: Object,
1240 ) {
@@ -1252,7 +1252,7 @@ export function warnForInsertedHydratedElement(
1252 }
1253
1254 export function warnForInsertedHydratedText(
1255 - parentNode: Element | Document,
1255 + parentNode: Element | Document | DocumentFragment,
1256 text: string,
1257 ) {
1258 if (__DEV__) {
packages/react-dom/src/client/ReactDOMHostConfig.js
+2 -1
@@ -107,7 +107,8 @@ export type EventTargetChildElement = {
107 };
108 export type Container =
109 | (Element & {_reactRootContainer?: FiberRoot, ...})
110 - | (Document & {_reactRootContainer?: FiberRoot, ...});
110 + | (Document & {_reactRootContainer?: FiberRoot, ...})
111 + | (DocumentFragment & {_reactRootContainer?: FiberRoot, ...});
112 export type Instance = Element;
113 export type TextInstance = Text;
114 export type SuspenseInstance = Comment & {_reactRetry?: () => void, ...};
packages/react-dom/src/client/ReactDOMRoot.js
+7 -6
@@ -7,7 +7,6 @@
7 * @flow
8 */
9
10 -import type {Container} from './ReactDOMHostConfig';
10 import type {MutableSource, ReactNodeList} from 'shared/ReactTypes';
11 import type {
12 FiberRoot,
@@ -165,7 +164,7 @@ ReactDOMHydrationRoot.prototype.unmount = ReactDOMRoot.prototype.unmount = funct
164 };
165
166 export function createRoot(
168 - container: Container,
167 + container: Element | DocumentFragment,
168 options?: CreateRootOptions,
169 ): RootType {
170 if (!isValidContainer(container)) {
@@ -235,8 +234,10 @@ export function createRoot(
234 );
235 markContainerAsRoot(root.current, container);
236
238 - const rootContainerElement =
239 - container.nodeType === COMMENT_NODE ? container.parentNode : container;
237 + const rootContainerElement: Document | Element | DocumentFragment =
238 + container.nodeType === COMMENT_NODE
239 + ? (container.parentNode: any)
240 + : container;
241 listenToAllSupportedEvents(rootContainerElement);
242
243 return new ReactDOMRoot(root);
@@ -253,7 +254,7 @@ function scheduleHydration(target: Node) {
254 ReactDOMHydrationRoot.prototype.unstable_scheduleHydration = scheduleHydration;
255
256 export function hydrateRoot(
256 - container: Container,
257 + container: Document | Element,
258 initialChildren: ReactNodeList,
259 options?: HydrateRootOptions,
260 ): RootType {
@@ -351,7 +352,7 @@ export function isValidContainerLegacy(node: any): boolean {
352 );
353 }
354
354 -function warnIfReactDOMContainerInDEV(container) {
355 +function warnIfReactDOMContainerInDEV(container: any) {
356 if (__DEV__) {
357 if (
358 container.nodeType === ELEMENT_NODE &&