@samitouri / QOS-React / commits / 17806594cc

Move createRoot/hydrateRoot to react-dom/client (#23385)

* Move createRoot/hydrateRoot to /client We want these APIs ideally to be imported separately from things you might use in arbitrary components (like flushSync). Those other methods are "isomorphic" to how the ReactDOM tree is rendered. Similar to hooks. E.g. importing flushSync into a component that only uses it on the client should ideally not also pull in the entry client implementation on the server. This also creates a nicer parity with /server where the roots are in a separate entry point. Unfortunately, I can't quite do this yet because we have some legacy APIs that we plan on removing (like findDOMNode) and we also haven't implemented flushSync using a flag like startTransition does yet. Another problem is that we currently encourage these APIs to be aliased by /profiling (or unstable_testing). In the future you don't have to alias them because you can just change your roots to just import those APIs and they'll still work with the isomorphic forms. Although we might also just use export conditions for them. For that all to work, I went with a different strategy for now where the real API is in / but it comes with a warning if you use it. If you instead import /client it disables the warning in a wrapper. That means that if you alias / then import /client that will inturn import the alias and it'll just work. In a future breaking changes (likely when we switch to ESM) we can just remove createRoot/hydrateRoot from / and move away from the aliasing strategy. * Update tests to import from react-dom/client * Fix fixtures * Update warnings * Add test for the warning * Update devtools * Change order of react-dom, react-dom/client alias I think the order matters here. The first one takes precedence. * Require react-dom through client so it can be aliased Co-authored-by: Andrew Clark <git@andrewclark.io>

Sebastian Markbåge committed Mar 1, 2022 at 00:13 UTC 17806594cc28284fe195f918e8d77de3516848ec
72 files changed +648 -356
fixtures/blocks/src/index.js
+1 -1
@@ -6,7 +6,7 @@
6 */
7
8 import React from 'react';
9 -import {createRoot} from 'react-dom';
9 +import {createRoot} from 'react-dom/client';
10 import './index.css';
11 import Router from './Router';
12
fixtures/concurrent/time-slicing/src/index.js
+1 -1
@@ -1,5 +1,5 @@
1 import React, {PureComponent, unstable_startTransition} from 'react';
2 -import {createRoot} from 'react-dom';
2 +import {createRoot} from 'react-dom/client';
3 import _ from 'lodash';
4 import Charts from './Charts';
5 import Clock from './Clock';
fixtures/ssr/src/index.js
+1 -1
@@ -1,5 +1,5 @@
1 import React from 'react';
2 -import {hydrateRoot} from 'react-dom';
2 +import {hydrateRoot} from 'react-dom/client';
3
4 import App from './components/App';
5
fixtures/ssr/yarn.lock
+9 -1
@@ -4265,7 +4265,7 @@ longest@^1.0.1:
4265 resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
4266 integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
4267
4268 -loose-envify@^1.0.0:
4268 +loose-envify@^1.0.0, loose-envify@^1.1.0:
4269 version "1.4.0"
4270 resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
4271 integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -5945,6 +5945,14 @@ sax@^1.2.1, sax@~1.2.1:
5945 resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
5946 integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
5947
5948 +scheduler@^0.20.1:
5949 + version "0.20.2"
5950 + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
5951 + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
5952 + dependencies:
5953 + loose-envify "^1.1.0"
5954 + object-assign "^4.1.1"
5955 +
5956 "semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0:
5957 version "5.7.1"
5958 resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
fixtures/ssr2/src/index.js
+1 -1
@@ -6,7 +6,7 @@
6 *
7 */
8
9 -import {hydrateRoot} from 'react-dom';
9 +import {hydrateRoot} from 'react-dom/client';
10 import App from './App';
11
12 hydrateRoot(document, <App assets={window.assetManifest} />);
packages/react-devtools-core/src/standalone.js
+2 -3
@@ -11,9 +11,8 @@ import {createElement} from 'react';
11 import {
12 // $FlowFixMe Flow does not yet know about flushSync()
13 flushSync,
14 - // $FlowFixMe Flow does not yet know about createRoot()
15 - createRoot,
16 -} from 'react-dom';
14 +} from 'react-dom/client';
15 +import {createRoot} from 'react-dom/client';
16 import Bridge from 'react-devtools-shared/src/bridge';
17 import Store from 'react-devtools-shared/src/devtools/store';
18 import {
packages/react-devtools-core/webpack.standalone.js
+1
@@ -64,6 +64,7 @@ module.exports = {
64 react: resolve(builtModulesDir, 'react'),
65 'react-debug-tools': resolve(builtModulesDir, 'react-debug-tools'),
66 'react-devtools-feature-flags': resolveFeatureFlags(featureFlagTarget),
67 + 'react-dom/client': resolve(builtModulesDir, 'react-dom/client'),
68 'react-dom': resolve(builtModulesDir, 'react-dom'),
69 'react-is': resolve(builtModulesDir, 'react-is'),
70 scheduler: resolve(builtModulesDir, 'scheduler'),
packages/react-devtools-extensions/webpack.config.js
+1
@@ -76,6 +76,7 @@ module.exports = {
76 react: resolve(builtModulesDir, 'react'),
77 'react-debug-tools': resolve(builtModulesDir, 'react-debug-tools'),
78 'react-devtools-feature-flags': resolveFeatureFlags(featureFlagTarget),
79 + 'react-dom/client': resolve(builtModulesDir, 'react-dom/client'),
80 'react-dom': resolve(builtModulesDir, 'react-dom'),
81 'react-is': resolve(builtModulesDir, 'react-is'),
82 scheduler: resolve(builtModulesDir, 'scheduler'),
packages/react-devtools-inline/README.md
+3 -5
@@ -60,7 +60,7 @@ const contentWindow = iframe.contentWindow;
60 const DevTools = initialize(contentWindow);
61 ```
62
63 -<sup>3</sup> Because the DevTools interface makes use of several new React APIs (e.g. suspense, concurrent mode) it should be rendered using either `ReactDOM.createRoot` or `ReactDOM.createSyncRoot`. **It should not be rendered with `ReactDOM.render`.**
63 +<sup>3</sup> Because the DevTools interface makes use of several new React APIs (e.g. suspense, concurrent mode) it should be rendered using `ReactDOMClient.createRoot`. **It should not be rendered with `ReactDOM.render`.**
64
65 ## Examples
66
@@ -110,8 +110,7 @@ const DevTools = initializeFrontend(contentWindow);
110 // as setting the src of the <iframe> would load a new page (without the injected backend).
111
112 // <DevTools /> interface can be rendered in the parent window at any time now...
113 -// Be sure to use either ReactDOM.createRoot()
114 -// or ReactDOM.createSyncRoot() to render this component.
113 +// Be sure to use ReactDOMClient.createRoot() to render this component.
114
115 // Let the backend know the frontend is ready and listening.
116 activateBackend(contentWindow);
@@ -154,8 +153,7 @@ const { contentWindow } = iframe;
153
154 // Initialize DevTools UI to listen to the iframe.
155 // This returns a React component we can render anywhere in the main window.
157 -// Be sure to use either ReactDOM.createRoot()
158 -// or ReactDOM.createSyncRoot() to render this component.
156 +// Be sure to use ReactDOMClient.createRoot() to render this component.
157 const DevTools = initialize(contentWindow);
158
159 // Let the backend know to initialize itself.
packages/react-devtools-inline/webpack.config.js
+1
@@ -51,6 +51,7 @@ module.exports = {
51 externals: {
52 react: 'react',
53 'react-dom': 'react-dom',
54 + 'react-dom/client': 'react-dom/client',
55 'react-is': 'react-is',
56 scheduler: 'scheduler',
57 },
packages/react-devtools-shared/src/__tests__/TimelineProfiler-test.js
+3 -3
@@ -11,7 +11,7 @@
11
12 describe('Timeline profiler', () => {
13 let React;
14 - let ReactDOM;
14 + let ReactDOMClient;
15 let Scheduler;
16 let renderHelper;
17 let renderRootHelper;
@@ -31,7 +31,7 @@ describe('Timeline profiler', () => {
31 };
32 renderRootHelper = element => {
33 const container = document.createElement('div');
34 - const root = ReactDOM.createRoot(container);
34 + const root = ReactDOMClient.createRoot(container);
35 root.render(element);
36 const unmountFn = () => root.unmount();
37 unmountFns.push(unmountFn);
@@ -39,7 +39,7 @@ describe('Timeline profiler', () => {
39 };
40
41 React = require('react');
42 - ReactDOM = require('react-dom');
42 + ReactDOMClient = require('react-dom/client');
43 Scheduler = require('scheduler');
44
45 store = global.store;
packages/react-devtools-shared/src/__tests__/console-test.js
+9 -9
@@ -7,7 +7,7 @@
7 * @flow
8 */
9 let React;
10 -let ReactDOM;
10 +let ReactDOMClient;
11 let act;
12 let fakeConsole;
13 let legacyRender;
@@ -53,7 +53,7 @@ describe('console', () => {
53 };
54
55 React = require('react');
56 - ReactDOM = require('react-dom');
56 + ReactDOMClient = require('react-dom/client');
57
58 const utils = require('./utils');
59 act = utils.act;
@@ -476,7 +476,7 @@ describe('console', () => {
476 global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false;
477
478 const container = document.createElement('div');
479 - const root = ReactDOM.createRoot(container);
479 + const root = ReactDOMClient.createRoot(container);
480
481 function App() {
482 fakeConsole.log('log');
@@ -515,7 +515,7 @@ describe('console', () => {
515 global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = true;
516
517 const container = document.createElement('div');
518 - const root = ReactDOM.createRoot(container);
518 + const root = ReactDOMClient.createRoot(container);
519
520 function App() {
521 fakeConsole.log('log');
@@ -557,7 +557,7 @@ describe('console', () => {
557 null,
558 );
559 const container = document.createElement('div');
560 - const root = ReactDOM.createRoot(container);
560 + const root = ReactDOMClient.createRoot(container);
561
562 function App() {
563 fakeConsole.log('log');
@@ -605,7 +605,7 @@ describe('console', () => {
605 null,
606 );
607 const container = document.createElement('div');
608 - const root = ReactDOM.createRoot(container);
608 + const root = ReactDOMClient.createRoot(container);
609
610 function App() {
611 fakeConsole.log('log');
@@ -639,7 +639,7 @@ describe('console', () => {
639 global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false;
640
641 const container = document.createElement('div');
642 - const root = ReactDOM.createRoot(container);
642 + const root = ReactDOMClient.createRoot(container);
643
644 const Intermediate = ({children}) => children;
645 const Parent = ({children}) => (
@@ -719,7 +719,7 @@ describe('console error', () => {
719 };
720
721 React = require('react');
722 - ReactDOM = require('react-dom');
722 + ReactDOMClient = require('react-dom/client');
723
724 const utils = require('./utils');
725 act = utils.act;
@@ -728,7 +728,7 @@ describe('console error', () => {
728
729 it('error in console log throws without interfering with logging', () => {
730 const container = document.createElement('div');
731 - const root = ReactDOM.createRoot(container);
731 + const root = ReactDOMClient.createRoot(container);
732
733 function App() {
734 fakeConsole.log('log');
packages/react-devtools-shared/src/__tests__/inspectedElement-test.js
+8 -6
@@ -16,6 +16,7 @@ import type Store from 'react-devtools-shared/src/devtools/store';
16 describe('InspectedElement', () => {
17 let React;
18 let ReactDOM;
19 + let ReactDOMClient;
20 let PropTypes;
21 let TestRenderer: ReactTestRenderer;
22 let bridge: FrontendBridge;
@@ -52,6 +53,7 @@ describe('InspectedElement', () => {
53
54 React = require('react');
55 ReactDOM = require('react-dom');
56 + ReactDOMClient = require('react-dom/client');
57 PropTypes = require('prop-types');
58 TestUtilsAct = require('jest-react').act;
59 TestRenderer = utils.requireTestRenderer();
@@ -506,7 +508,7 @@ describe('InspectedElement', () => {
508 });
509
510 const container = document.createElement('div');
509 - const root = ReactDOM.createRoot(container);
511 + const root = ReactDOMClient.createRoot(container);
512 await utils.actAsync(() => root.render(<Target a={1} b="abc" />));
513
514 expect(targetRenderCount).toBe(1);
@@ -2091,25 +2093,25 @@ describe('InspectedElement', () => {
2093 expect(inspectedElement.rootType).toMatchInlineSnapshot(`"render()"`);
2094 });
2095
2094 - it('should display the root type for ReactDOM.hydrateRoot', async () => {
2096 + it('should display the root type for ReactDOMClient.hydrateRoot', async () => {
2097 const Example = () => <div />;
2098
2099 await utils.actAsync(() => {
2100 const container = document.createElement('div');
2101 container.innerHTML = '<div></div>';
2100 - ReactDOM.hydrateRoot(container).render(<Example />);
2102 + ReactDOMClient.hydrateRoot(container).render(<Example />);
2103 }, false);
2104
2105 const inspectedElement = await inspectElementAtIndex(0);
2106 expect(inspectedElement.rootType).toMatchInlineSnapshot(`"hydrateRoot()"`);
2107 });
2108
2107 - it('should display the root type for ReactDOM.createRoot', async () => {
2109 + it('should display the root type for ReactDOMClient.createRoot', async () => {
2110 const Example = () => <div />;
2111
2112 await utils.actAsync(() => {
2113 const container = document.createElement('div');
2112 - ReactDOM.createRoot(container).render(<Example />);
2114 + ReactDOMClient.createRoot(container).render(<Example />);
2115 }, false);
2116
2117 const inspectedElement = await inspectElementAtIndex(0);
@@ -2133,7 +2135,7 @@ describe('InspectedElement', () => {
2135
2136 await utils.actAsync(() => {
2137 const container = document.createElement('div');
2136 - ReactDOM.createRoot(container).render(<Example />);
2138 + ReactDOMClient.createRoot(container).render(<Example />);
2139 }, false);
2140
2141 shouldThrow = true;
packages/react-devtools-shared/src/__tests__/preprocessData-test.js
+36 -13
@@ -12,6 +12,7 @@
12 describe('Timeline profiler', () => {
13 let React;
14 let ReactDOM;
15 + let ReactDOMClient;
16 let Scheduler;
17 let utils;
18
@@ -76,6 +77,7 @@ describe('Timeline profiler', () => {
77
78 React = require('react');
79 ReactDOM = require('react-dom');
80 + ReactDOMClient = require('react-dom/client');
81 Scheduler = require('scheduler');
82
83 setPerformanceMock = require('react-devtools-shared/src/backend/profilingHooks')
@@ -797,7 +799,7 @@ describe('Timeline profiler', () => {
799 return true;
800 }
801
800 - const root = ReactDOM.createRoot(document.createElement('div'));
802 + const root = ReactDOMClient.createRoot(document.createElement('div'));
803 utils.act(() => root.render(<App />));
804
805 const data = await preprocessData([
@@ -1222,7 +1224,7 @@ describe('Timeline profiler', () => {
1224
1225 const testMarks = [creactCpuProfilerSample()];
1226
1225 - const root = ReactDOM.createRoot(document.createElement('div'));
1227 + const root = ReactDOMClient.createRoot(document.createElement('div'));
1228 utils.act(() =>
1229 root.render(
1230 <React.Suspense fallback="Loading...">
@@ -1342,7 +1344,9 @@ describe('Timeline profiler', () => {
1344 // Advance the clock by some arbitrary amount.
1345 startTime += 50000;
1346
1345 - const root = ReactDOM.createRoot(document.createElement('div'));
1347 + const root = ReactDOMClient.createRoot(
1348 + document.createElement('div'),
1349 + );
1350
1351 // Temporarily turn off the act environment, since we're intentionally using Scheduler instead.
1352 global.IS_REACT_ACT_ENVIRONMENT = false;
@@ -1398,7 +1402,9 @@ describe('Timeline profiler', () => {
1402 return didMount;
1403 }
1404
1401 - const root = ReactDOM.createRoot(document.createElement('div'));
1405 + const root = ReactDOMClient.createRoot(
1406 + document.createElement('div'),
1407 + );
1408 utils.act(() => {
1409 root.render(<Component />);
1410 });
@@ -1434,7 +1440,9 @@ describe('Timeline profiler', () => {
1440 }
1441 }
1442
1437 - const root = ReactDOM.createRoot(document.createElement('div'));
1443 + const root = ReactDOMClient.createRoot(
1444 + document.createElement('div'),
1445 + );
1446 utils.act(() => {
1447 root.render(<Component />);
1448 });
@@ -1471,7 +1479,9 @@ describe('Timeline profiler', () => {
1479
1480 const cpuProfilerSample = creactCpuProfilerSample();
1481
1474 - const root = ReactDOM.createRoot(document.createElement('div'));
1482 + const root = ReactDOMClient.createRoot(
1483 + document.createElement('div'),
1484 + );
1485 utils.act(() => {
1486 root.render(<Component />);
1487 });
@@ -1530,7 +1540,9 @@ describe('Timeline profiler', () => {
1540
1541 const cpuProfilerSample = creactCpuProfilerSample();
1542
1533 - const root = ReactDOM.createRoot(document.createElement('div'));
1543 + const root = ReactDOMClient.createRoot(
1544 + document.createElement('div'),
1545 + );
1546 utils.act(() => {
1547 root.render(<Component />);
1548 });
@@ -1599,7 +1611,9 @@ describe('Timeline profiler', () => {
1611
1612 const cpuProfilerSample = creactCpuProfilerSample();
1613
1602 - const root = ReactDOM.createRoot(document.createElement('div'));
1614 + const root = ReactDOMClient.createRoot(
1615 + document.createElement('div'),
1616 + );
1617 utils.act(() => {
1618 root.render(<Component />);
1619 });
@@ -1664,7 +1678,9 @@ describe('Timeline profiler', () => {
1678
1679 const cpuProfilerSample = creactCpuProfilerSample();
1680
1667 - const root = ReactDOM.createRoot(document.createElement('div'));
1681 + const root = ReactDOMClient.createRoot(
1682 + document.createElement('div'),
1683 + );
1684 utils.act(() => {
1685 root.render(<Component />);
1686 });
@@ -1730,7 +1746,9 @@ describe('Timeline profiler', () => {
1746 const testMarks = [creactCpuProfilerSample()];
1747
1748 // Mount and commit the app
1733 - const root = ReactDOM.createRoot(document.createElement('div'));
1749 + const root = ReactDOMClient.createRoot(
1750 + document.createElement('div'),
1751 + );
1752 utils.act(() =>
1753 root.render(
1754 <ErrorBoundary>
@@ -1775,7 +1793,9 @@ describe('Timeline profiler', () => {
1793 }
1794
1795 // Mount and commit the app
1778 - const root = ReactDOM.createRoot(document.createElement('div'));
1796 + const root = ReactDOMClient.createRoot(
1797 + document.createElement('div'),
1798 + );
1799 utils.act(() =>
1800 root.render(
1801 <React.Suspense fallback="Loading...">
@@ -1830,7 +1850,9 @@ describe('Timeline profiler', () => {
1850 }
1851
1852 // Mount and commit the app
1833 - const root = ReactDOM.createRoot(document.createElement('div'));
1853 + const root = ReactDOMClient.createRoot(
1854 + document.createElement('div'),
1855 + );
1856 utils.act(() =>
1857 root.render(
1858 <React.Suspense fallback="Loading...">
@@ -1881,6 +1903,7 @@ describe('Timeline profiler', () => {
1903
1904 React = require('react');
1905 ReactDOM = require('react-dom');
1906 + ReactDOMClient = require('react-dom/client');
1907 Scheduler = require('scheduler');
1908
1909 store = global.store;
@@ -2071,7 +2094,7 @@ describe('Timeline profiler', () => {
2094 return true;
2095 }
2096
2074 - const root = ReactDOM.createRoot(document.createElement('div'));
2097 + const root = ReactDOMClient.createRoot(document.createElement('div'));
2098 utils.act(() => root.render(<App />));
2099 utils.act(() => store.profilerStore.stopProfiling());
2100
packages/react-devtools-shared/src/__tests__/profilingCache-test.js
+5 -3
@@ -15,6 +15,7 @@ describe('ProfilingCache', () => {
15 let PropTypes;
16 let React;
17 let ReactDOM;
18 + let ReactDOMClient;
19 let Scheduler;
20 let TestRenderer: ReactTestRenderer;
21 let bridge: FrontendBridge;
@@ -36,6 +37,7 @@ describe('ProfilingCache', () => {
37 PropTypes = require('prop-types');
38 React = require('react');
39 ReactDOM = require('react-dom');
40 + ReactDOMClient = require('react-dom/client');
41 Scheduler = require('scheduler');
42 TestRenderer = utils.requireTestRenderer();
43 });
@@ -771,7 +773,7 @@ describe('ProfilingCache', () => {
773 return <>{!childUnmounted && <Child />}</>;
774 }
775
774 - const root = ReactDOM.createRoot(document.createElement('div'));
776 + const root = ReactDOMClient.createRoot(document.createElement('div'));
777 utils.act(() => root.render(<App />));
778 utils.act(() => store.profilerStore.startProfiling());
779 utils.act(() => setChildUnmounted(true));
@@ -805,7 +807,7 @@ describe('ProfilingCache', () => {
807 return <>{!childUnmounted && <Child />}</>;
808 }
809
808 - const root = ReactDOM.createRoot(document.createElement('div'));
810 + const root = ReactDOMClient.createRoot(document.createElement('div'));
811 utils.act(() => root.render(<App />));
812 utils.act(() => store.profilerStore.startProfiling());
813 utils.act(() => setChildUnmounted(true));
@@ -834,7 +836,7 @@ describe('ProfilingCache', () => {
836 return <>{!childUnmounted && <Child />}</>;
837 }
838
837 - const root = ReactDOM.createRoot(document.createElement('div'));
839 + const root = ReactDOMClient.createRoot(document.createElement('div'));
840 utils.act(() => root.render(<App />));
841 utils.act(() => store.profilerStore.startProfiling());
842 utils.act(() => setChildUnmounted(true));
packages/react-devtools-shared/src/__tests__/profilingCommitTreeBuilder-test.js
+4 -4
@@ -12,7 +12,7 @@ import type Store from 'react-devtools-shared/src/devtools/store';
12
13 describe('commit tree', () => {
14 let React;
15 - let ReactDOM;
15 + let ReactDOMClient;
16 let Scheduler;
17 let TestRenderer: TestRendererType;
18 let legacyRender;
@@ -30,7 +30,7 @@ describe('commit tree', () => {
30 store.recordChangeDescriptions = true;
31
32 React = require('react');
33 - ReactDOM = require('react-dom');
33 + ReactDOMClient = require('react-dom/client');
34 Scheduler = require('scheduler');
35 TestRenderer = utils.requireTestRenderer();
36 });
@@ -146,7 +146,7 @@ describe('commit tree', () => {
146
147 it('should support Lazy components (createRoot)', async () => {
148 const container = document.createElement('div');
149 - const root = ReactDOM.createRoot(container);
149 + const root = ReactDOMClient.createRoot(container);
150
151 utils.act(() => store.profilerStore.startProfiling());
152 utils.act(() => root.render(<App renderChildren={true} />));
@@ -219,7 +219,7 @@ describe('commit tree', () => {
219
220 it('should support Lazy components that are unmounted before resolving (createRoot)', async () => {
221 const container = document.createElement('div');
222 - const root = ReactDOM.createRoot(container);
222 + const root = ReactDOMClient.createRoot(container);
223
224 utils.act(() => store.profilerStore.startProfiling());
225 utils.act(() => root.render(<App renderChildren={true} />));
packages/react-devtools-shared/src/__tests__/profilingHostRoot-test.js
+4 -4
@@ -9,7 +9,7 @@
9
10 describe('profiling HostRoot', () => {
11 let React;
12 - let ReactDOM;
12 + let ReactDOMClient;
13 let Scheduler;
14 let legacyRender;
15 let store: Store;
@@ -29,7 +29,7 @@ describe('profiling HostRoot', () => {
29 store = global.store;
30
31 React = require('react');
32 - ReactDOM = require('react-dom');
32 + ReactDOMClient = require('react-dom/client');
33 Scheduler = require('scheduler');
34
35 effectDurations = [];
@@ -91,7 +91,7 @@ describe('profiling HostRoot', () => {
91 utils.act(() => store.profilerStore.startProfiling());
92 utils.act(() => {
93 const container = document.createElement('div');
94 - const root = ReactDOM.createRoot(container);
94 + const root = ReactDOMClient.createRoot(container);
95 root.render(<App />);
96 });
97 utils.act(() => store.profilerStore.stopProfiling());
@@ -124,7 +124,7 @@ describe('profiling HostRoot', () => {
124 }
125
126 const container = document.createElement('div');
127 - const root = ReactDOM.createRoot(container);
127 + const root = ReactDOMClient.createRoot(container);
128
129 utils.act(() => store.profilerStore.startProfiling());
130 utils.act(() => root.render(<App />));
packages/react-devtools-shared/src/__tests__/store-test.js
+10 -6
@@ -10,6 +10,7 @@
10 describe('Store', () => {
11 let React;
12 let ReactDOM;
13 + let ReactDOMClient;
14 let agent;
15 let act;
16 let bridge;
@@ -25,6 +26,7 @@ describe('Store', () => {
26
27 React = require('react');
28 ReactDOM = require('react-dom');
29 + ReactDOMClient = require('react-dom/client');
30
31 const utils = require('./utils');
32 act = utils.act;
@@ -120,7 +122,9 @@ describe('Store', () => {
122 const Component = () => null;
123
124 const container = document.createElement('div');
123 - const root = ReactDOM.createRoot(container, {unstable_strictMode: true});
125 + const root = ReactDOMClient.createRoot(container, {
126 + unstable_strictMode: true,
127 + });
128 act(() => {
129 root.render(<App />);
130 });
@@ -134,7 +138,7 @@ describe('Store', () => {
138 const Component = () => null;
139
140 const container = document.createElement('div');
137 - const root = ReactDOM.createRoot(container);
141 + const root = ReactDOMClient.createRoot(container);
142 act(() => {
143 root.render(<App />);
144 });
@@ -152,7 +156,7 @@ describe('Store', () => {
156 const Component = () => null;
157
158 const container = document.createElement('div');
155 - const root = ReactDOM.createRoot(container);
159 + const root = ReactDOMClient.createRoot(container);
160 act(() => {
161 root.render(<App />);
162 });
@@ -466,7 +470,7 @@ describe('Store', () => {
470 );
471
472 const container = document.createElement('div');
469 - const root = ReactDOM.createRoot(container);
473 + const root = ReactDOMClient.createRoot(container);
474 act(() => {
475 root.render(<Wrapper shouldSuspense={true} />);
476 });
@@ -1070,7 +1074,7 @@ describe('Store', () => {
1074
1075 it('should support Lazy components in (createRoot)', async () => {
1076 const container = document.createElement('div');
1073 - const root = ReactDOM.createRoot(container);
1077 + const root = ReactDOMClient.createRoot(container);
1078
1079 // Render once to start fetching the lazy component
1080 act(() => root.render(<App renderChildren={true} />));
@@ -1106,7 +1110,7 @@ describe('Store', () => {
1110
1111 it('should support Lazy components that are unmounted before they finish loading in (createRoot)', async () => {
1112 const container = document.createElement('div');
1109 - const root = ReactDOM.createRoot(container);
1113 + const root = ReactDOMClient.createRoot(container);
1114
1115 // Render once to start fetching the lazy component
1116 act(() => root.render(<App renderChildren={true} />));
packages/react-devtools-shared/src/__tests__/storeStressTestConcurrent-test.js
+22 -22
@@ -9,7 +9,7 @@
9
10 describe('StoreStressConcurrent', () => {
11 let React;
12 - let ReactDOM;
12 + let ReactDOMClient;
13 let act;
14 let actAsync;
15 let bridge;
@@ -22,7 +22,7 @@ describe('StoreStressConcurrent', () => {
22 store.collapseNodesByDefault = false;
23
24 React = require('react');
25 - ReactDOM = require('react-dom');
25 + ReactDOMClient = require('react-dom/client');
26 act = require('./utils').act;
27 // TODO: Figure out recommendation for concurrent mode tests, then replace
28 // this helper with the real thing.
@@ -67,7 +67,7 @@ describe('StoreStressConcurrent', () => {
67 // 1. Render a normal version of [a, b, c, d, e].
68 let container = document.createElement('div');
69 // $FlowFixMe
70 - let root = ReactDOM.createRoot(container);
70 + let root = ReactDOMClient.createRoot(container);
71 act(() => root.render(<Parent>{[a, b, c, d, e]}</Parent>));
72 expect(store).toMatchInlineSnapshot(
73 `
@@ -151,7 +151,7 @@ describe('StoreStressConcurrent', () => {
151 // Ensure fresh mount.
152 container = document.createElement('div');
153 // $FlowFixMe
154 - root = ReactDOM.createRoot(container);
154 + root = ReactDOMClient.createRoot(container);
155
156 // Verify mounting 'abcde'.
157 act(() => root.render(<Parent>{cases[i]}</Parent>));
@@ -181,7 +181,7 @@ describe('StoreStressConcurrent', () => {
181 // There'll be no unmounting until the very end.
182 container = document.createElement('div');
183 // $FlowFixMe
184 - root = ReactDOM.createRoot(container);
184 + root = ReactDOMClient.createRoot(container);
185 for (let i = 0; i < cases.length; i++) {
186 // Verify mounting 'abcde'.
187 act(() => root.render(<Parent>{cases[i]}</Parent>));
@@ -248,7 +248,7 @@ describe('StoreStressConcurrent', () => {
248 let container = document.createElement('div');
249 for (let i = 0; i < steps.length; i++) {
250 // $FlowFixMe
251 - const root = ReactDOM.createRoot(container);
251 + const root = ReactDOMClient.createRoot(container);
252 act(() => root.render(<Root>{steps[i]}</Root>));
253 // We snapshot each step once so it doesn't regress.
254 snapshots.push(print(store));
@@ -320,7 +320,7 @@ describe('StoreStressConcurrent', () => {
320 for (let j = 0; j < steps.length; j++) {
321 container = document.createElement('div');
322 // $FlowFixMe
323 - const root = ReactDOM.createRoot(container);
323 + const root = ReactDOMClient.createRoot(container);
324 act(() => root.render(<Root>{steps[i]}</Root>));
325 expect(print(store)).toMatch(snapshots[i]);
326 act(() => root.render(<Root>{steps[j]}</Root>));
@@ -337,7 +337,7 @@ describe('StoreStressConcurrent', () => {
337 for (let j = 0; j < steps.length; j++) {
338 container = document.createElement('div');
339 // $FlowFixMe
340 - const root = ReactDOM.createRoot(container);
340 + const root = ReactDOMClient.createRoot(container);
341 act(() =>
342 root.render(
343 <Root>
@@ -410,7 +410,7 @@ describe('StoreStressConcurrent', () => {
410 let container = document.createElement('div');
411 for (let i = 0; i < steps.length; i++) {
412 // $FlowFixMe
413 - const root = ReactDOM.createRoot(container);
413 + const root = ReactDOMClient.createRoot(container);
414 act(() =>
415 root.render(
416 <Root>
@@ -513,7 +513,7 @@ describe('StoreStressConcurrent', () => {
513 // 2. Verify check Suspense can render same steps as initial fallback content.
514 for (let i = 0; i < steps.length; i++) {
515 // $FlowFixMe
516 - const root = ReactDOM.createRoot(container);
516 + const root = ReactDOMClient.createRoot(container);
517 act(() =>
518 root.render(
519 <Root>
@@ -538,7 +538,7 @@ describe('StoreStressConcurrent', () => {
538 // Always start with a fresh container and steps[i].
539 container = document.createElement('div');
540 // $FlowFixMe
541 - const root = ReactDOM.createRoot(container);
541 + const root = ReactDOMClient.createRoot(container);
542 act(() =>
543 root.render(
544 <Root>
@@ -584,7 +584,7 @@ describe('StoreStressConcurrent', () => {
584 // Always start with a fresh container and steps[i].
585 container = document.createElement('div');
586 // $FlowFixMe
587 - const root = ReactDOM.createRoot(container);
587 + const root = ReactDOMClient.createRoot(container);
588 act(() =>
589 root.render(
590 <Root>
@@ -642,7 +642,7 @@ describe('StoreStressConcurrent', () => {
642 // Always start with a fresh container and steps[i].
643 container = document.createElement('div');
644 // $FlowFixMe
645 - const root = ReactDOM.createRoot(container);
645 + const root = ReactDOMClient.createRoot(container);
646 act(() =>
647 root.render(
648 <Root>
@@ -692,7 +692,7 @@ describe('StoreStressConcurrent', () => {
692 // Always start with a fresh container and steps[i].
693 container = document.createElement('div');
694 // $FlowFixMe
695 - const root = ReactDOM.createRoot(container);
695 + const root = ReactDOMClient.createRoot(container);
696 act(() =>
697 root.render(
698 <Root>
@@ -746,7 +746,7 @@ describe('StoreStressConcurrent', () => {
746 // Always start with a fresh container and steps[i].
747 container = document.createElement('div');
748 // $FlowFixMe
749 - const root = ReactDOM.createRoot(container);
749 + const root = ReactDOMClient.createRoot(container);
750 act(() =>
751 root.render(
752 <Root>
@@ -901,7 +901,7 @@ describe('StoreStressConcurrent', () => {
901 let container = document.createElement('div');
902 for (let i = 0; i < steps.length; i++) {
903 // $FlowFixMe
904 - const root = ReactDOM.createRoot(container);
904 + const root = ReactDOMClient.createRoot(container);
905 act(() =>
906 root.render(
907 <Root>
@@ -925,7 +925,7 @@ describe('StoreStressConcurrent', () => {
925 const fallbackSnapshots = [];
926 for (let i = 0; i < steps.length; i++) {
927 // $FlowFixMe
928 - const root = ReactDOM.createRoot(container);
928 + const root = ReactDOMClient.createRoot(container);
929 act(() =>
930 root.render(
931 <Root>
@@ -1059,7 +1059,7 @@ describe('StoreStressConcurrent', () => {
1059 // Always start with a fresh container and steps[i].
1060 container = document.createElement('div');
1061 // $FlowFixMe
1062 - const root = ReactDOM.createRoot(container);
1062 + const root = ReactDOMClient.createRoot(container);
1063 act(() =>
1064 root.render(
1065 <Root>
@@ -1111,7 +1111,7 @@ describe('StoreStressConcurrent', () => {
1111 // Always start with a fresh container and steps[i].
1112 container = document.createElement('div');
1113 // $FlowFixMe
1114 - const root = ReactDOM.createRoot(container);
1114 + const root = ReactDOMClient.createRoot(container);
1115 act(() =>
1116 root.render(
1117 <Root>
@@ -1178,7 +1178,7 @@ describe('StoreStressConcurrent', () => {
1178 // Always start with a fresh container and steps[i].
1179 container = document.createElement('div');
1180 // $FlowFixMe
1181 - const root = ReactDOM.createRoot(container);
1181 + const root = ReactDOMClient.createRoot(container);
1182 act(() =>
1183 root.render(
1184 <Root>
@@ -1230,7 +1230,7 @@ describe('StoreStressConcurrent', () => {
1230 // Always start with a fresh container and steps[i].
1231 container = document.createElement('div');
1232 // $FlowFixMe
1233 - const root = ReactDOM.createRoot(container);
1233 + const root = ReactDOMClient.createRoot(container);
1234 act(() =>
1235 root.render(
1236 <Root>
@@ -1282,7 +1282,7 @@ describe('StoreStressConcurrent', () => {
1282 // Always start with a fresh container and steps[i].
1283 container = document.createElement('div');
1284 // $FlowFixMe
1285 - const root = ReactDOM.createRoot(container);
1285 + const root = ReactDOMClient.createRoot(container);
1286 act(() =>
1287 root.render(
1288 <Root>
packages/react-devtools-shell/src/app/index.js
+2 -6
@@ -3,12 +3,8 @@
3 // This test harness mounts each test app as a separate root to test multi-root applications.
4
5 import {createElement} from 'react';
6 -import {
7 - // $FlowFixMe Flow does not yet know about createRoot()
8 - createRoot,
9 - render,
10 - unmountComponentAtNode,
11 -} from 'react-dom';
6 +import {createRoot} from 'react-dom/client';
7 +import {render, unmountComponentAtNode} from 'react-dom';
8 import DeeplyNestedComponents from './DeeplyNestedComponents';
9 import Iframe from './Iframe';
10 import EditableProps from './EditableProps';
packages/react-devtools-shell/src/e2e/app.js
+2 -2
@@ -4,6 +4,7 @@
4
5 import * as React from 'react';
6 import * as ReactDOM from 'react-dom';
7 +import * as ReactDOMClient from 'react-dom/client';
8
9 const container = document.createElement('div');
10
@@ -13,8 +14,7 @@ const container = document.createElement('div');
14 // so that it can load things other than just ToDoList.
15 const App = require('./apps/ListApp').default;
16
16 -// $FlowFixMe Flow doesn't know about createRoot() yet.
17 -const root = ReactDOM.createRoot(container);
17 +const root = ReactDOMClient.createRoot(container);
18 root.render(<App />);
19
20 // ReactDOM Test Selector APIs used by Playwright e2e tests
packages/react-devtools-shell/src/e2e/devtools.js
+2 -1
@@ -1,5 +1,6 @@
1 import * as React from 'react';
2 import * as ReactDOM from 'react-dom';
3 +import * as ReactDOMClient from 'react-dom/client';
4 import {
5 activate as activateBackend,
6 initialize as initializeBackend,
@@ -33,7 +34,7 @@ function init(appIframe, devtoolsContainer, appSource) {
34
35 inject(contentDocument, appSource, () => {
36 // $FlowFixMe Flow doesn't know about createRoot() yet.
36 - ReactDOM.createRoot(devtoolsContainer).render(
37 + ReactDOMClient.createRoot(devtoolsContainer).render(
38 <DevTools
39 hookNamesModuleLoaderFunction={hookNamesModuleLoaderFunction}
40 showTabBar={true}
packages/react-devtools-shell/webpack.config.js
+1
@@ -60,6 +60,7 @@ const config = {
60 react: resolve(builtModulesDir, 'react'),
61 'react-debug-tools': resolve(builtModulesDir, 'react-debug-tools'),
62 'react-devtools-feature-flags': resolveFeatureFlags('shell'),
63 + 'react-dom/client': resolve(builtModulesDir, 'react-dom/client'),
64 'react-dom': resolve(builtModulesDir, 'react-dom/unstable_testing'),
65 'react-is': resolve(builtModulesDir, 'react-is'),
66 scheduler: resolve(builtModulesDir, 'scheduler'),
packages/react-dom/client.js new
+57
@@ -0,0 +1,57 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +'use strict';
11 +
12 +import type {Container} from './src/client/ReactDOMHostConfig';
13 +import type {ReactNodeList} from 'shared/ReactTypes';
14 +import type {
15 + RootType,
16 + HydrateRootOptions,
17 + CreateRootOptions,
18 +} from './src/client/ReactDOMRoot';
19 +
20 +import {
21 + createRoot as createRootImpl,
22 + hydrateRoot as hydrateRootImpl,
23 + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as Internals,
24 +} from './';
25 +
26 +export function createRoot(
27 + container: Container,
28 + options?: CreateRootOptions,
29 +): RootType {
30 + if (__DEV__) {
31 + Internals.usingClientEntryPoint = true;
32 + }
33 + try {
34 + return createRootImpl(container, options);
35 + } finally {
36 + if (__DEV__) {
37 + Internals.usingClientEntryPoint = false;
38 + }
39 + }
40 +}
41 +
42 +export function hydrateRoot(
43 + container: Container,
44 + children: ReactNodeList,
45 + options?: HydrateRootOptions,
46 +): RootType {
47 + if (__DEV__) {
48 + Internals.usingClientEntryPoint = true;
49 + }
50 + try {
51 + return hydrateRootImpl(container, children, options);
52 + } finally {
53 + if (__DEV__) {
54 + Internals.usingClientEntryPoint = false;
55 + }
56 + }
57 +}
packages/react-dom/npm/client.js new
+25
@@ -0,0 +1,25 @@
1 +'use strict';
2 +
3 +var m = require('react-dom');
4 +if (process.env.NODE_ENV === 'production') {
5 + exports.createRoot = m.createRoot;
6 + exports.hydrateRoot = m.hydrateRoot;
7 +} else {
8 + var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
9 + exports.createRoot = function(c, o) {
10 + i.usingClientEntryPoint = true;
11 + try {
12 + return m.createRoot(c, o);
13 + } finally {
14 + i.usingClientEntryPoint = false;
15 + }
16 + };
17 + exports.hydrateRoot = function(c, h, o) {
18 + i.usingClientEntryPoint = true;
19 + try {
20 + return m.hydrateRoot(c, h, o);
21 + } finally {
22 + i.usingClientEntryPoint = false;
23 + }
24 + };
25 +}
packages/react-dom/package.json
+2
@@ -27,6 +27,7 @@
27 "LICENSE",
28 "README.md",
29 "index.js",
30 + "client.js",
31 "profiling.js",
32 "server.js",
33 "server.browser.js",
@@ -38,6 +39,7 @@
39 ],
40 "exports": {
41 ".": "./index.js",
42 + "./client": "./client.js",
43 "./server": {
44 "deno": "./server.browser.js",
45 "worker": "./server.browser.js",
packages/react-dom/src/__tests__/ReactDOMConsoleErrorReporting-test.js
+10 -8
@@ -11,6 +11,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
11 let act;
12 let React;
13 let ReactDOM;
14 + let ReactDOMClient;
15
16 let ErrorBoundary;
17 let NoError;
@@ -22,6 +23,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
23 act = require('jest-react').act;
24 React = require('react');
25 ReactDOM = require('react-dom');
26 + ReactDOMClient = require('react-dom/client');
27
28 ErrorBoundary = class extends React.Component {
29 state = {error: null};
@@ -49,7 +51,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
51 window.removeEventListener('error', windowOnError);
52 });
53
52 - describe('ReactDOM.createRoot', () => {
54 + describe('ReactDOMClient.createRoot', () => {
55 it('logs errors during event handlers', () => {
56 spyOnDevAndProd(console, 'error');
57
@@ -64,7 +66,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
66 );
67 }
68
67 - const root = ReactDOM.createRoot(container);
69 + const root = ReactDOMClient.createRoot(container);
70 act(() => {
71 root.render(<Foo />);
72 });
@@ -150,7 +152,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
152 throw Error('Boom');
153 }
154
153 - const root = ReactDOM.createRoot(container);
155 + const root = ReactDOMClient.createRoot(container);
156 expect(() => {
157 act(() => {
158 root.render(<Foo />);
@@ -230,7 +232,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
232 throw Error('Boom');
233 }
234
233 - const root = ReactDOM.createRoot(container);
235 + const root = ReactDOMClient.createRoot(container);
236 act(() => {
237 root.render(
238 <ErrorBoundary>
@@ -315,7 +317,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
317 return null;
318 }
319
318 - const root = ReactDOM.createRoot(container);
320 + const root = ReactDOMClient.createRoot(container);
321 expect(() => {
322 act(() => {
323 root.render(<Foo />);
@@ -383,7 +385,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
385 return null;
386 }
387
386 - const root = ReactDOM.createRoot(container);
388 + const root = ReactDOMClient.createRoot(container);
389 act(() => {
390 root.render(
391 <ErrorBoundary>
@@ -453,7 +455,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
455 return null;
456 }
457
456 - const root = ReactDOM.createRoot(container);
458 + const root = ReactDOMClient.createRoot(container);
459 expect(() => {
460 act(() => {
461 root.render(<Foo />);
@@ -521,7 +523,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
523 return null;
524 }
525
524 - const root = ReactDOM.createRoot(container);
526 + const root = ReactDOMClient.createRoot(container);
527 act(() => {
528 root.render(
529 <ErrorBoundary>
packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js
+13 -11
@@ -12,6 +12,7 @@
12 let React;
13
14 let ReactDOM;
15 +let ReactDOMClient;
16 let Scheduler;
17 let act;
18
@@ -28,6 +29,7 @@ describe('ReactDOMFiberAsync', () => {
29 container = document.createElement('div');
30 React = require('react');
31 ReactDOM = require('react-dom');
32 + ReactDOMClient = require('react-dom/client');
33 act = require('jest-react').act;
34 Scheduler = require('scheduler');
35
@@ -184,7 +186,7 @@ describe('ReactDOMFiberAsync', () => {
186 );
187 }
188 }
187 - const root = ReactDOM.createRoot(container);
189 + const root = ReactDOMClient.createRoot(container);
190 root.render(<Counter />);
191 Scheduler.unstable_flushAll();
192 expect(asyncValueRef.current.textContent).toBe('');
@@ -204,7 +206,7 @@ describe('ReactDOMFiberAsync', () => {
206 });
207
208 it('top-level updates are concurrent', () => {
207 - const root = ReactDOM.createRoot(container);
209 + const root = ReactDOMClient.createRoot(container);
210 root.render(<div>Hi</div>);
211 expect(container.textContent).toEqual('');
212 Scheduler.unstable_flushAll();
@@ -226,7 +228,7 @@ describe('ReactDOMFiberAsync', () => {
228 }
229 }
230
229 - const root = ReactDOM.createRoot(container);
231 + const root = ReactDOMClient.createRoot(container);
232 root.render(<Component />);
233 expect(container.textContent).toEqual('');
234 Scheduler.unstable_flushAll();
@@ -256,7 +258,7 @@ describe('ReactDOMFiberAsync', () => {
258 }
259 }
260
259 - const root = ReactDOM.createRoot(container);
261 + const root = ReactDOMClient.createRoot(container);
262 root.render(<Component />);
263 Scheduler.unstable_flushAll();
264
@@ -298,7 +300,7 @@ describe('ReactDOMFiberAsync', () => {
300 return this.state.counter;
301 }
302 }
301 - const root = ReactDOM.createRoot(container);
303 + const root = ReactDOMClient.createRoot(container);
304 root.render(<Counter />);
305 Scheduler.unstable_flushAll();
306 expect(container.textContent).toEqual('0');
@@ -401,7 +403,7 @@ describe('ReactDOMFiberAsync', () => {
403 );
404 }
405
404 - const root = ReactDOM.createRoot(container);
406 + const root = ReactDOMClient.createRoot(container);
407 await act(async () => {
408 root.render(<Form />);
409 });
@@ -452,7 +454,7 @@ describe('ReactDOMFiberAsync', () => {
454 );
455 }
456
455 - const root = ReactDOM.createRoot(container);
457 + const root = ReactDOMClient.createRoot(container);
458 await act(async () => {
459 root.render(<Form />);
460 });
@@ -511,7 +513,7 @@ describe('ReactDOMFiberAsync', () => {
513 );
514 }
515
514 - const root = ReactDOM.createRoot(container);
516 + const root = ReactDOMClient.createRoot(container);
517 await act(async () => {
518 root.render(<Form />);
519 });
@@ -576,7 +578,7 @@ describe('ReactDOMFiberAsync', () => {
578 });
579
580 it('updates flush without yielding in the next event', () => {
579 - const root = ReactDOM.createRoot(container);
581 + const root = ReactDOMClient.createRoot(container);
582
583 function Text(props) {
584 Scheduler.unstable_yieldValue(props.text);
@@ -621,7 +623,7 @@ describe('ReactDOMFiberAsync', () => {
623 return <button ref={ref}>new</button>;
624 }
625
624 - const oldRoot = ReactDOM.createRoot(container);
626 + const oldRoot = ReactDOMClient.createRoot(container);
627 act(() => {
628 oldRoot.render(<OldApp />);
629 });
@@ -633,7 +635,7 @@ describe('ReactDOMFiberAsync', () => {
635 expect(container.textContent).toBe('');
636
637 // We can now render a new one.
636 - const newRoot = ReactDOM.createRoot(container);
638 + const newRoot = ReactDOMClient.createRoot(container);
639 ReactDOM.flushSync(() => {
640 newRoot.render(<NewApp />);
641 });
packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
+22 -19
@@ -13,7 +13,7 @@ let JSDOM;
13 let Stream;
14 let Scheduler;
15 let React;
16 -let ReactDOM;
16 +let ReactDOMClient;
17 let ReactDOMFizzServer;
18 let Suspense;
19 let SuspenseList;
@@ -36,7 +36,7 @@ describe('ReactDOMFizzServer', () => {
36 JSDOM = require('jsdom').JSDOM;
37 Scheduler = require('scheduler');
38 React = require('react');
39 - ReactDOM = require('react-dom');
39 + ReactDOMClient = require('react-dom/client');
40 if (__EXPERIMENTAL__) {
41 ReactDOMFizzServer = require('react-dom/server');
42 }
@@ -346,7 +346,7 @@ describe('ReactDOMFizzServer', () => {
346 // Client-side
347 const [HydrateApp, hydrateResolve] = makeApp();
348 await act(async () => {
349 - ReactDOM.hydrateRoot(container, <HydrateApp />);
349 + ReactDOMClient.hydrateRoot(container, <HydrateApp />);
350 });
351
352 expect(getVisibleChildren(container)).toEqual(
@@ -424,7 +424,7 @@ describe('ReactDOMFizzServer', () => {
424 window.__INIT__ = function() {
425 bootstrapped = true;
426 // Attempt to hydrate the content.
427 - ReactDOM.hydrateRoot(container, <App isClient={true} />, {
427 + ReactDOMClient.hydrateRoot(container, <App isClient={true} />, {
428 onRecoverableError(error) {
429 Scheduler.unstable_yieldValue(error.message);
430 },
@@ -538,7 +538,7 @@ describe('ReactDOMFizzServer', () => {
538 expect(loggedErrors).toEqual([]);
539
540 // Attempt to hydrate the content.
541 - ReactDOM.hydrateRoot(container, <App isClient={true} />, {
541 + ReactDOMClient.hydrateRoot(container, <App isClient={true} />, {
542 onRecoverableError(error) {
543 Scheduler.unstable_yieldValue(error.message);
544 },
@@ -611,7 +611,7 @@ describe('ReactDOMFizzServer', () => {
611 window.__INIT__ = function() {
612 bootstrapped = true;
613 // Attempt to hydrate the content.
614 - ReactDOM.hydrateRoot(container, <App />);
614 + ReactDOMClient.hydrateRoot(container, <App />);
615 };
616
617 await act(async () => {
@@ -708,7 +708,7 @@ describe('ReactDOMFizzServer', () => {
708 expect(loggedErrors).toEqual([]);
709
710 // Attempt to hydrate the content.
711 - ReactDOM.hydrateRoot(container, <App />);
711 + ReactDOMClient.hydrateRoot(container, <App />);
712 Scheduler.unstable_flushAll();
713
714 // We're still loading because we're waiting for the server to stream more content.
@@ -779,7 +779,10 @@ describe('ReactDOMFizzServer', () => {
779 pipe(writable);
780 });
781
782 - const root = ReactDOM.hydrateRoot(container, <App showMore={false} />);
782 + const root = ReactDOMClient.hydrateRoot(
783 + container,
784 + <App showMore={false} />,
785 + );
786 Scheduler.unstable_flushAll();
787
788 // We're not hydrated yet.
@@ -846,7 +849,7 @@ describe('ReactDOMFizzServer', () => {
849 // We're still showing a fallback.
850
851 // Attempt to hydrate the content.
849 - ReactDOM.hydrateRoot(container, <App />, {
852 + ReactDOMClient.hydrateRoot(container, <App />, {
853 onRecoverableError(error) {
854 Scheduler.unstable_yieldValue(error.message);
855 },
@@ -1542,7 +1545,7 @@ describe('ReactDOMFizzServer', () => {
1545 // We're still showing a fallback.
1546
1547 // Attempt to hydrate the content.
1545 - ReactDOM.hydrateRoot(container, <App isClient={true} />, {
1548 + ReactDOMClient.hydrateRoot(container, <App isClient={true} />, {
1549 onRecoverableError(error) {
1550 Scheduler.unstable_yieldValue(error.message);
1551 },
@@ -1731,7 +1734,7 @@ describe('ReactDOMFizzServer', () => {
1734
1735 let root;
1736 await act(async () => {
1734 - root = ReactDOM.hydrateRoot(container, <App isClient={false} />);
1737 + root = ReactDOMClient.hydrateRoot(container, <App isClient={false} />);
1738 Scheduler.unstable_flushAll();
1739 await jest.runAllTimers();
1740 });
@@ -1817,7 +1820,7 @@ describe('ReactDOMFizzServer', () => {
1820 });
1821 expect(Scheduler).toHaveYielded(['server']);
1822
1820 - ReactDOM.hydrateRoot(container, <App />, {
1823 + ReactDOMClient.hydrateRoot(container, <App />, {
1824 onRecoverableError(error) {
1825 Scheduler.unstable_yieldValue(
1826 'Log recoverable error: ' + error.message,
@@ -1917,7 +1920,7 @@ describe('ReactDOMFizzServer', () => {
1920 });
1921 expect(Scheduler).toHaveYielded(['server']);
1922
1920 - ReactDOM.hydrateRoot(container, <App />, {
1923 + ReactDOMClient.hydrateRoot(container, <App />, {
1924 onRecoverableError(error) {
1925 Scheduler.unstable_yieldValue(
1926 'Log recoverable error: ' + error.message,
@@ -2019,7 +2022,7 @@ describe('ReactDOMFizzServer', () => {
2022 // Hydrate the tree. Child will throw during hydration, but not when it
2023 // falls back to client rendering.
2024 isClient = true;
2022 - ReactDOM.hydrateRoot(container, <App />, {
2025 + ReactDOMClient.hydrateRoot(container, <App />, {
2026 onRecoverableError(error) {
2027 Scheduler.unstable_yieldValue(error.message);
2028 },
@@ -2110,7 +2113,7 @@ describe('ReactDOMFizzServer', () => {
2113 // Hydrate the tree. Child will throw during hydration, but not when it
2114 // falls back to client rendering.
2115 isClient = true;
2113 - ReactDOM.hydrateRoot(container, <App />, {
2116 + ReactDOMClient.hydrateRoot(container, <App />, {
2117 onRecoverableError(error) {
2118 Scheduler.unstable_yieldValue(error.message);
2119 },
@@ -2198,7 +2201,7 @@ describe('ReactDOMFizzServer', () => {
2201
2202 // Hydrate the tree. Child will throw during render.
2203 isClient = true;
2201 - ReactDOM.hydrateRoot(container, <App />, {
2204 + ReactDOMClient.hydrateRoot(container, <App />, {
2205 onRecoverableError(error) {
2206 Scheduler.unstable_yieldValue(
2207 'Log recoverable error: ' + error.message,
@@ -2280,7 +2283,7 @@ describe('ReactDOMFizzServer', () => {
2283 // Hydrate the tree. Child will throw during hydration, but not when it
2284 // falls back to client rendering.
2285 isClient = true;
2283 - ReactDOM.hydrateRoot(container, <App />, {
2286 + ReactDOMClient.hydrateRoot(container, <App />, {
2287 onRecoverableError(error) {
2288 Scheduler.unstable_yieldValue(error.message);
2289 },
@@ -2349,7 +2352,7 @@ describe('ReactDOMFizzServer', () => {
2352 );
2353 }
2354
2352 - const root = ReactDOM.createRoot(container, {
2355 + const root = ReactDOMClient.createRoot(container, {
2356 onRecoverableError(error) {
2357 Scheduler.unstable_yieldValue(
2358 'Logged a recoverable error: ' + error.message,
@@ -2431,7 +2434,7 @@ describe('ReactDOMFizzServer', () => {
2434 // Hydrate the tree. Child will throw during hydration, but not when it
2435 // falls back to client rendering.
2436 isClient = true;
2434 - ReactDOM.hydrateRoot(container, <App />, {
2437 + ReactDOMClient.hydrateRoot(container, <App />, {
2438 onRecoverableError(error) {
2439 Scheduler.unstable_yieldValue(
2440 'Logged recoverable error: ' + error.message,
packages/react-dom/src/__tests__/ReactDOMFizzShellHydration-test.js
+5 -5
@@ -9,7 +9,7 @@
9
10 let JSDOM;
11 let React;
12 -let ReactDOM;
12 +let ReactDOMClient;
13 let Scheduler;
14 let clientAct;
15 let ReactDOMFizzServer;
@@ -27,7 +27,7 @@ describe('ReactDOMFizzShellHydration', () => {
27 jest.resetModules();
28 JSDOM = require('jsdom').JSDOM;
29 React = require('react');
30 - ReactDOM = require('react-dom');
30 + ReactDOMClient = require('react-dom/client');
31 Scheduler = require('scheduler');
32 clientAct = require('jest-react').act;
33 ReactDOMFizzServer = require('react-dom/server');
@@ -180,7 +180,7 @@ describe('ReactDOMFizzShellHydration', () => {
180
181 // Hydration suspends because the data for the shell hasn't loaded yet
182 await clientAct(async () => {
183 - ReactDOM.hydrateRoot(container, <App />);
183 + ReactDOMClient.hydrateRoot(container, <App />);
184 });
185 expect(Scheduler).toHaveYielded(['Suspend! [Shell]']);
186 expect(div.current).toBe(null);
@@ -201,7 +201,7 @@ describe('ReactDOMFizzShellHydration', () => {
201 return <AsyncText text="Shell" />;
202 }
203
204 - const root = ReactDOM.createRoot(container);
204 + const root = ReactDOMClient.createRoot(container);
205 await clientAct(async () => {
206 root.render(<App />);
207 });
@@ -232,7 +232,7 @@ describe('ReactDOMFizzShellHydration', () => {
232
233 // Hydration suspends because the data for the shell hasn't loaded yet
234 const root = await clientAct(async () => {
235 - return ReactDOM.hydrateRoot(container, <App />, {
235 + return ReactDOMClient.hydrateRoot(container, <App />, {
236 onRecoverableError(error) {
237 Scheduler.unstable_yieldValue(error.message);
238 },
packages/react-dom/src/__tests__/ReactDOMHooks-test.js
+3 -1
@@ -11,6 +11,7 @@
11
12 let React;
13 let ReactDOM;
14 +let ReactDOMClient;
15 let Scheduler;
16 let act;
17
@@ -22,6 +23,7 @@ describe('ReactDOMHooks', () => {
23
24 React = require('react');
25 ReactDOM = require('react-dom');
26 + ReactDOMClient = require('react-dom/client');
27 Scheduler = require('scheduler');
28 act = require('jest-react').act;
29
@@ -127,7 +129,7 @@ describe('ReactDOMHooks', () => {
129 const inputRef = createRef();
130 const labelRef = createRef();
131
130 - const root = ReactDOM.createRoot(container);
132 + const root = ReactDOMClient.createRoot(container);
133 root.render(<Example inputRef={inputRef} labelRef={labelRef} />);
134
135 Scheduler.unstable_flushAll();
packages/react-dom/src/__tests__/ReactDOMImageLoad-test.internal.js
+10 -8
@@ -13,6 +13,7 @@ let React;
13 let Scheduler;
14 // let ReactCache;
15 let ReactDOM;
16 +let ReactDOMClient;
17 // let Suspense;
18 let originalCreateElement;
19 // let TextResource;
@@ -89,6 +90,7 @@ describe('ReactDOMImageLoad', () => {
90 Scheduler = require('scheduler');
91 // ReactCache = require('react-cache');
92 ReactDOM = require('react-dom');
93 + ReactDOMClient = require('react-dom/client');
94 // Suspense = React.Suspense;
95
96 onLoadSpy = jest.fn(reactEvent => {
@@ -181,7 +183,7 @@ describe('ReactDOMImageLoad', () => {
183
184 it('captures the load event if it happens before commit phase and replays it between layout and passive effects', async function() {
185 const container = document.createElement('div');
184 - const root = ReactDOM.createRoot(container);
186 + const root = ReactDOMClient.createRoot(container);
187
188 React.startTransition(() =>
189 root.render(
@@ -221,7 +223,7 @@ describe('ReactDOMImageLoad', () => {
223
224 it('captures the load event if it happens after commit phase and replays it', async function() {
225 const container = document.createElement('div');
224 - const root = ReactDOM.createRoot(container);
226 + const root = ReactDOMClient.createRoot(container);
227
228 React.startTransition(() =>
229 root.render(
@@ -251,7 +253,7 @@ describe('ReactDOMImageLoad', () => {
253
254 it('it replays the last load event when more than one fire before the end of the layout phase completes', async function() {
255 const container = document.createElement('div');
254 - const root = ReactDOM.createRoot(container);
256 + const root = ReactDOMClient.createRoot(container);
257
258 function Base() {
259 const [src, setSrc] = React.useState('a');
@@ -302,7 +304,7 @@ describe('ReactDOMImageLoad', () => {
304
305 it('replays load events that happen in passive phase after the passive phase.', async function() {
306 const container = document.createElement('div');
305 - const root = ReactDOM.createRoot(container);
307 + const root = ReactDOMClient.createRoot(container);
308
309 root.render(
310 <PhaseMarkers>
@@ -328,7 +330,7 @@ describe('ReactDOMImageLoad', () => {
330
331 it('captures and suppresses the load event if it happens before passive effects and a cascading update causes the img to be removed', async function() {
332 const container = document.createElement('div');
331 - const root = ReactDOM.createRoot(container);
333 + const root = ReactDOMClient.createRoot(container);
334
335 function ChildSuppressing({children}) {
336 const [showChildren, update] = React.useState(true);
@@ -377,7 +379,7 @@ describe('ReactDOMImageLoad', () => {
379
380 it('captures and suppresses the load event if it happens before passive effects and a cascading update causes the img to be removed, alternate', async function() {
381 const container = document.createElement('div');
380 - const root = ReactDOM.createRoot(container);
382 + const root = ReactDOMClient.createRoot(container);
383
384 function Switch({children}) {
385 const [shouldShow, updateShow] = React.useState(true);
@@ -456,7 +458,7 @@ describe('ReactDOMImageLoad', () => {
458 // }
459
460 // const container = document.createElement('div');
459 - // const root = ReactDOM.createRoot(container);
461 + // const root = ReactDOMClient.createRoot(container);
462
463 // React.startTransition(() => root.render(<SuspendingWithImage />));
464
@@ -531,7 +533,7 @@ describe('ReactDOMImageLoad', () => {
533 }
534
535 const container = document.createElement('div');
534 - const root = ReactDOM.createRoot(container);
536 + const root = ReactDOMClient.createRoot(container);
537
538 root.render(<Base />);
539
packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js
+10 -8
@@ -12,6 +12,7 @@
12 let React;
13
14 let ReactDOM;
15 +let ReactDOMClient;
16 let Scheduler;
17 let act;
18
@@ -23,6 +24,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
24 container = document.createElement('div');
25 React = require('react');
26 ReactDOM = require('react-dom');
27 + ReactDOMClient = require('react-dom/client');
28 Scheduler = require('scheduler');
29 act = require('jest-react').act;
30
@@ -65,7 +67,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
67 );
68 }
69
68 - const root = ReactDOM.createRoot(container);
70 + const root = ReactDOMClient.createRoot(container);
71 await act(() => {
72 root.render(<Form />);
73 });
@@ -121,7 +123,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
123 );
124 }
125
124 - const root = ReactDOM.createRoot(container);
126 + const root = ReactDOMClient.createRoot(container);
127 root.render(<Form />);
128 // Flush
129 Scheduler.unstable_flushAll();
@@ -181,7 +183,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
183 );
184 }
185
184 - const root = ReactDOM.createRoot(container);
186 + const root = ReactDOMClient.createRoot(container);
187 root.render(<Form />);
188 // Flush
189 Scheduler.unstable_flushAll();
@@ -212,7 +214,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
214 });
215
216 it('mouse over should be user-blocking but not discrete', async () => {
215 - const root = ReactDOM.createRoot(container);
217 + const root = ReactDOMClient.createRoot(container);
218
219 const target = React.createRef(null);
220 function Foo() {
@@ -242,7 +244,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
244 });
245
246 it('mouse enter should be user-blocking but not discrete', async () => {
245 - const root = ReactDOM.createRoot(container);
247 + const root = ReactDOMClient.createRoot(container);
248
249 const target = React.createRef(null);
250 function Foo() {
@@ -274,7 +276,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
276 });
277
278 it('continuous native events flush as expected', async () => {
277 - const root = ReactDOM.createRoot(container);
279 + const root = ReactDOMClient.createRoot(container);
280
281 const target = React.createRef(null);
282 function Foo({hovered}) {
@@ -313,7 +315,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
315 });
316
317 it('should batch inside native events', async () => {
316 - const root = ReactDOM.createRoot(container);
318 + const root = ReactDOMClient.createRoot(container);
319
320 const target = React.createRef(null);
321 function Foo() {
@@ -349,7 +351,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
351 });
352
353 it('should not flush discrete events at the end of outermost batchedUpdates', async () => {
352 - const root = ReactDOM.createRoot(container);
354 + const root = ReactDOMClient.createRoot(container);
355
356 let target;
357 function Foo() {
packages/react-dom/src/__tests__/ReactDOMNestedEvents-test.js
+3 -3
@@ -11,7 +11,7 @@
11
12 describe('ReactDOMNestedEvents', () => {
13 let React;
14 - let ReactDOM;
14 + let ReactDOMClient;
15 let Scheduler;
16 let act;
17 let useState;
@@ -19,7 +19,7 @@ describe('ReactDOMNestedEvents', () => {
19 beforeEach(() => {
20 jest.resetModules();
21 React = require('react');
22 - ReactDOM = require('react-dom');
22 + ReactDOMClient = require('react-dom/client');
23 Scheduler = require('scheduler');
24 act = require('jest-react').act;
25 useState = React.useState;
@@ -55,7 +55,7 @@ describe('ReactDOMNestedEvents', () => {
55
56 const container = document.createElement('div');
57 document.body.appendChild(container);
58 - const root = ReactDOM.createRoot(container);
58 + const root = ReactDOMClient.createRoot(container);
59
60 await act(async () => {
61 root.render(<App />);
packages/react-dom/src/__tests__/ReactDOMRoot-test.js
+57 -35
@@ -11,6 +11,7 @@
11
12 let React = require('react');
13 let ReactDOM = require('react-dom');
14 +let ReactDOMClient = require('react-dom/client');
15 let ReactDOMServer = require('react-dom/server');
16 let Scheduler = require('scheduler');
17 let act;
@@ -24,6 +25,7 @@ describe('ReactDOMRoot', () => {
25 container = document.createElement('div');
26 React = require('react');
27 ReactDOM = require('react-dom');
28 + ReactDOMClient = require('react-dom/client');
29 ReactDOMServer = require('react-dom/server');
30 Scheduler = require('scheduler');
31 act = require('jest-react').act;
@@ -31,15 +33,35 @@ describe('ReactDOMRoot', () => {
33 });
34
35 it('renders children', () => {
34 - const root = ReactDOM.createRoot(container);
36 + const root = ReactDOMClient.createRoot(container);
37 root.render(<div>Hi</div>);
38 Scheduler.unstable_flushAll();
39 expect(container.textContent).toEqual('Hi');
40 });
41
42 + it('warns if you import createRoot from react-dom', async () => {
43 + expect(() => ReactDOM.createRoot(container)).toErrorDev(
44 + 'You are importing createRoot from "react-dom" which is not supported. ' +
45 + 'You should instead import it from "react-dom/client".',
46 + {
47 + withoutStack: true,
48 + },
49 + );
50 + });
51 +
52 + it('warns if you import hydrateRoot from react-dom', async () => {
53 + expect(() => ReactDOM.hydrateRoot(container, null)).toErrorDev(
54 + 'You are importing hydrateRoot from "react-dom" which is not supported. ' +
55 + 'You should instead import it from "react-dom/client".',
56 + {
57 + withoutStack: true,
58 + },
59 + );
60 + });
61 +
62 it('warns if a callback parameter is provided to render', () => {
63 const callback = jest.fn();
42 - const root = ReactDOM.createRoot(container);
64 + const root = ReactDOMClient.createRoot(container);
65 expect(() =>
66 root.render(<div>Hi</div>, callback),
67 ).toErrorDev(
@@ -56,7 +78,7 @@ describe('ReactDOMRoot', () => {
78 return 'Child';
79 }
80
59 - const root = ReactDOM.createRoot(container);
81 + const root = ReactDOMClient.createRoot(container);
82 expect(() => root.render(<App />, {})).toErrorDev(
83 'You passed a second argument to root.render(...) but it only accepts ' +
84 'one argument.',
@@ -71,7 +93,7 @@ describe('ReactDOMRoot', () => {
93 return 'Child';
94 }
95
74 - const root = ReactDOM.createRoot(container);
96 + const root = ReactDOMClient.createRoot(container);
97 expect(() => root.render(<App />, container)).toErrorDev(
98 'You passed a container to the second argument of root.render(...). ' +
99 "You don't need to pass it again since you already passed it to create " +
@@ -84,7 +106,7 @@ describe('ReactDOMRoot', () => {
106
107 it('warns if a callback parameter is provided to unmount', () => {
108 const callback = jest.fn();
87 - const root = ReactDOM.createRoot(container);
109 + const root = ReactDOMClient.createRoot(container);
110 root.render(<div>Hi</div>);
111 expect(() =>
112 root.unmount(callback),
@@ -98,7 +120,7 @@ describe('ReactDOMRoot', () => {
120 });
121
122 it('unmounts children', () => {
101 - const root = ReactDOM.createRoot(container);
123 + const root = ReactDOMClient.createRoot(container);
124 root.render(<div>Hi</div>);
125 Scheduler.unstable_flushAll();
126 expect(container.textContent).toEqual('Hi');
@@ -121,7 +143,7 @@ describe('ReactDOMRoot', () => {
143 // Does not hydrate by default
144 const container1 = document.createElement('div');
145 container1.innerHTML = markup;
124 - const root1 = ReactDOM.createRoot(container1);
146 + const root1 = ReactDOMClient.createRoot(container1);
147 root1.render(
148 <div>
149 <span />
@@ -131,7 +153,7 @@ describe('ReactDOMRoot', () => {
153
154 const container2 = document.createElement('div');
155 container2.innerHTML = markup;
134 - ReactDOM.hydrateRoot(
156 + ReactDOMClient.hydrateRoot(
157 container2,
158 <div>
159 <span />
@@ -163,7 +185,7 @@ describe('ReactDOMRoot', () => {
185
186 it('clears existing children', async () => {
187 container.innerHTML = '<div>a</div><div>b</div>';
166 - const root = ReactDOM.createRoot(container);
188 + const root = ReactDOMClient.createRoot(container);
189 root.render(
190 <div>
191 <span>c</span>
@@ -184,12 +206,12 @@ describe('ReactDOMRoot', () => {
206
207 it('throws a good message on invalid containers', () => {
208 expect(() => {
187 - ReactDOM.createRoot(<div>Hi</div>);
209 + ReactDOMClient.createRoot(<div>Hi</div>);
210 }).toThrow('createRoot(...): Target container is not a DOM element.');
211 });
212
213 it('warns when rendering with legacy API into createRoot() container', () => {
192 - const root = ReactDOM.createRoot(container);
214 + const root = ReactDOMClient.createRoot(container);
215 root.render(<div>Hi</div>);
216 Scheduler.unstable_flushAll();
217 expect(container.textContent).toEqual('Hi');
@@ -199,7 +221,7 @@ describe('ReactDOMRoot', () => {
221 [
222 // We care about this warning:
223 'You are calling ReactDOM.render() on a container that was previously ' +
202 - 'passed to ReactDOM.createRoot(). This is not supported. ' +
224 + 'passed to ReactDOMClient.createRoot(). This is not supported. ' +
225 'Did you mean to call root.render(element)?',
226 // This is more of a symptom but restructuring the code to avoid it isn't worth it:
227 'Replacing React-rendered children with a new root component.',
@@ -212,7 +234,7 @@ describe('ReactDOMRoot', () => {
234 });
235
236 it('warns when hydrating with legacy API into createRoot() container', () => {
215 - const root = ReactDOM.createRoot(container);
237 + const root = ReactDOMClient.createRoot(container);
238 root.render(<div>Hi</div>);
239 Scheduler.unstable_flushAll();
240 expect(container.textContent).toEqual('Hi');
@@ -222,7 +244,7 @@ describe('ReactDOMRoot', () => {
244 [
245 // We care about this warning:
246 'You are calling ReactDOM.hydrate() on a container that was previously ' +
225 - 'passed to ReactDOM.createRoot(). This is not supported. ' +
247 + 'passed to ReactDOMClient.createRoot(). This is not supported. ' +
248 'Did you mean to call hydrateRoot(container, element)?',
249 // This is more of a symptom but restructuring the code to avoid it isn't worth it:
250 'Replacing React-rendered children with a new root component.',
@@ -232,7 +254,7 @@ describe('ReactDOMRoot', () => {
254 });
255
256 it('warns when unmounting with legacy API (no previous content)', () => {
235 - const root = ReactDOM.createRoot(container);
257 + const root = ReactDOMClient.createRoot(container);
258 root.render(<div>Hi</div>);
259 Scheduler.unstable_flushAll();
260 expect(container.textContent).toEqual('Hi');
@@ -243,7 +265,7 @@ describe('ReactDOMRoot', () => {
265 [
266 // We care about this warning:
267 'You are calling ReactDOM.unmountComponentAtNode() on a container that was previously ' +
246 - 'passed to ReactDOM.createRoot(). This is not supported. Did you mean to call root.unmount()?',
268 + 'passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.unmount()?',
269 // This is more of a symptom but restructuring the code to avoid it isn't worth it:
270 "The node you're attempting to unmount was rendered by React and is not a top-level container.",
271 ],
@@ -261,7 +283,7 @@ describe('ReactDOMRoot', () => {
283 // Currently createRoot().render() doesn't clear this.
284 container.appendChild(document.createElement('div'));
285 // The rest is the same as test above.
264 - const root = ReactDOM.createRoot(container);
286 + const root = ReactDOMClient.createRoot(container);
287 root.render(<div>Hi</div>);
288 Scheduler.unstable_flushAll();
289 expect(container.textContent).toEqual('Hi');
@@ -287,20 +309,20 @@ describe('ReactDOMRoot', () => {
309 it('warns when passing legacy container to createRoot()', () => {
310 ReactDOM.render(<div>Hi</div>, container);
311 expect(() => {
290 - ReactDOM.createRoot(container);
312 + ReactDOMClient.createRoot(container);
313 }).toErrorDev(
292 - 'You are calling ReactDOM.createRoot() on a container that was previously ' +
314 + 'You are calling ReactDOMClient.createRoot() on a container that was previously ' +
315 'passed to ReactDOM.render(). This is not supported.',
316 {withoutStack: true},
317 );
318 });
319
320 it('warns when creating two roots managing the same container', () => {
299 - ReactDOM.createRoot(container);
321 + ReactDOMClient.createRoot(container);
322 expect(() => {
301 - ReactDOM.createRoot(container);
323 + ReactDOMClient.createRoot(container);
324 }).toErrorDev(
303 - 'You are calling ReactDOM.createRoot() on a container that ' +
325 + 'You are calling ReactDOMClient.createRoot() on a container that ' +
326 'has already been passed to createRoot() before. Instead, call ' +
327 'root.render() on the existing root instead if you want to update it.',
328 {withoutStack: true},
@@ -308,15 +330,15 @@ describe('ReactDOMRoot', () => {
330 });
331
332 it('does not warn when creating second root after first one is unmounted', () => {
311 - const root = ReactDOM.createRoot(container);
333 + const root = ReactDOMClient.createRoot(container);
334 root.unmount();
335 Scheduler.unstable_flushAll();
314 - ReactDOM.createRoot(container); // No warning
336 + ReactDOMClient.createRoot(container); // No warning
337 });
338
339 it('warns if creating a root on the document.body', async () => {
340 expect(() => {
319 - ReactDOM.createRoot(document.body);
341 + ReactDOMClient.createRoot(document.body);
342 }).toErrorDev(
343 'createRoot(): Creating roots directly with document.body is ' +
344 'discouraged, since its children are often manipulated by third-party ' +
@@ -328,7 +350,7 @@ describe('ReactDOMRoot', () => {
350 });
351
352 it('warns if updating a root that has had its contents removed', async () => {
331 - const root = ReactDOM.createRoot(container);
353 + const root = ReactDOMClient.createRoot(container);
354 root.render(<div>Hi</div>);
355 Scheduler.unstable_flushAll();
356 container.innerHTML = '';
@@ -345,7 +367,7 @@ describe('ReactDOMRoot', () => {
367 });
368
369 it('opts-in to concurrent default updates', async () => {
348 - const root = ReactDOM.createRoot(container, {
370 + const root = ReactDOMClient.createRoot(container, {
371 unstable_concurrentUpdatesByDefault: true,
372 });
373
@@ -377,7 +399,7 @@ describe('ReactDOMRoot', () => {
399 });
400
401 it('unmount is synchronous', async () => {
380 - const root = ReactDOM.createRoot(container);
402 + const root = ReactDOMClient.createRoot(container);
403 await act(async () => {
404 root.render('Hi');
405 });
@@ -391,7 +413,7 @@ describe('ReactDOMRoot', () => {
413 });
414
415 it('throws if an unmounted root is updated', async () => {
394 - const root = ReactDOM.createRoot(container);
416 + const root = ReactDOMClient.createRoot(container);
417 await act(async () => {
418 root.render('Hi');
419 });
@@ -406,9 +428,9 @@ describe('ReactDOMRoot', () => {
428
429 it('warns if root is unmounted inside an effect', async () => {
430 const container1 = document.createElement('div');
409 - const root1 = ReactDOM.createRoot(container1);
431 + const root1 = ReactDOMClient.createRoot(container1);
432 const container2 = document.createElement('div');
411 - const root2 = ReactDOM.createRoot(container2);
433 + const root2 = ReactDOMClient.createRoot(container2);
434
435 function App({step}) {
436 useEffect(() => {
@@ -441,10 +463,10 @@ describe('ReactDOMRoot', () => {
463 div.innerHTML = '<!-- react-mount-point-unstable -->';
464 const commentNode = div.childNodes[0];
465
444 - expect(() => ReactDOM.createRoot(commentNode)).toThrow(
466 + expect(() => ReactDOMClient.createRoot(commentNode)).toThrow(
467 'createRoot(...): Target container is not a DOM element.',
468 );
447 - expect(() => ReactDOM.hydrateRoot(commentNode)).toThrow(
469 + expect(() => ReactDOMClient.hydrateRoot(commentNode)).toThrow(
470 'hydrateRoot(...): Target container is not a DOM element.',
471 );
472
@@ -454,7 +476,7 @@ describe('ReactDOMRoot', () => {
476
477 it('warn if no children passed to hydrateRoot', async () => {
478 expect(() =>
457 - ReactDOM.hydrateRoot(container),
479 + ReactDOMClient.hydrateRoot(container),
480 ).toErrorDev(
481 'Must provide initial children as second argument to hydrateRoot.',
482 {withoutStack: true},
@@ -466,7 +488,7 @@ describe('ReactDOMRoot', () => {
488 return 'Child';
489 }
490
469 - expect(() => ReactDOM.createRoot(container, <App />)).toErrorDev(
491 + expect(() => ReactDOMClient.createRoot(container, <App />)).toErrorDev(
492 'You passed a JSX element to createRoot. You probably meant to call ' +
493 'root.render instead',
494 {
packages/react-dom/src/__tests__/ReactDOMSafariMicrotaskBug-test.js
+3 -3
@@ -11,7 +11,7 @@
11
12 let React;
13
14 -let ReactDOM;
14 +let ReactDOMClient;
15 let act;
16
17 describe('ReactDOMSafariMicrotaskBug-test', () => {
@@ -35,7 +35,7 @@ describe('ReactDOMSafariMicrotaskBug-test', () => {
35 jest.resetModules();
36 container = document.createElement('div');
37 React = require('react');
38 - ReactDOM = require('react-dom');
38 + ReactDOMClient = require('react-dom/client');
39 act = require('jest-react').act;
40
41 document.body.appendChild(container);
@@ -62,7 +62,7 @@ describe('ReactDOMSafariMicrotaskBug-test', () => {
62 </div>
63 );
64 }
65 - const root = ReactDOM.createRoot(container);
65 + const root = ReactDOMClient.createRoot(container);
66 await act(async () => {
67 root.render(<Foo />);
68 });
packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js
+69 -51
@@ -11,6 +11,7 @@
11
12 let React = require('react');
13 let ReactDOM;
14 +let ReactDOMClient;
15 let ReactDOMServer;
16 let Scheduler;
17 let ReactFeatureFlags;
@@ -100,6 +101,7 @@ describe('ReactDOMServerPartialHydration', () => {
101
102 React = require('react');
103 ReactDOM = require('react-dom');
104 + ReactDOMClient = require('react-dom/client');
105 act = require('jest-react').act;
106 ReactDOMServer = require('react-dom/server');
107 Scheduler = require('scheduler');
@@ -164,7 +166,7 @@ describe('ReactDOMServerPartialHydration', () => {
166 // On the client we don't have all data yet but we want to start
167 // hydrating anyway.
168 suspend = true;
167 - ReactDOM.hydrateRoot(container, <App />);
169 + ReactDOMClient.hydrateRoot(container, <App />);
170 Scheduler.unstable_flushAll();
171 jest.runAllTimers();
172
@@ -217,7 +219,7 @@ describe('ReactDOMServerPartialHydration', () => {
219 // On the client we don't have all data yet but we want to start
220 // hydrating anyway.
221 suspend = true;
220 - ReactDOM.hydrateRoot(container, <App />, {
222 + ReactDOMClient.hydrateRoot(container, <App />, {
223 onRecoverableError(error) {
224 Scheduler.unstable_yieldValue(error.message);
225 },
@@ -310,7 +312,7 @@ describe('ReactDOMServerPartialHydration', () => {
312 suspend = true;
313 client = true;
314
313 - ReactDOM.hydrateRoot(container, <App />, {
315 + ReactDOMClient.hydrateRoot(container, <App />, {
316 onRecoverableError(error) {
317 Scheduler.unstable_yieldValue(error.message);
318 },
@@ -426,7 +428,7 @@ describe('ReactDOMServerPartialHydration', () => {
428 // hydrating anyway.
429 suspend = true;
430 suspend2 = true;
429 - const root = ReactDOM.hydrateRoot(container, <App />, {
431 + const root = ReactDOMClient.hydrateRoot(container, <App />, {
432 onHydrated(node) {
433 hydrated.push(node);
434 },
@@ -483,7 +485,7 @@ describe('ReactDOMServerPartialHydration', () => {
485 const container = document.createElement('div');
486 container.innerHTML = finalHTML;
487
486 - ReactDOM.hydrateRoot(container, <App />);
488 + ReactDOMClient.hydrateRoot(container, <App />);
489 Scheduler.unstable_flushAll();
490 jest.runAllTimers();
491
@@ -517,7 +519,7 @@ describe('ReactDOMServerPartialHydration', () => {
519
520 expect(() => {
521 act(() => {
520 - ReactDOM.hydrateRoot(container, <App hasB={false} />, {
522 + ReactDOMClient.hydrateRoot(container, <App hasB={false} />, {
523 onRecoverableError(error) {
524 Scheduler.unstable_yieldValue(error.message);
525 },
@@ -590,7 +592,7 @@ describe('ReactDOMServerPartialHydration', () => {
592
593 shouldSuspend = true;
594 act(() => {
593 - ReactDOM.hydrateRoot(container, <App hasB={false} />);
595 + ReactDOMClient.hydrateRoot(container, <App hasB={false} />);
596 });
597
598 resolve();
@@ -651,7 +653,7 @@ describe('ReactDOMServerPartialHydration', () => {
653
654 expect(() => {
655 act(() => {
654 - ReactDOM.hydrateRoot(container, <App hasB={false} />, {
656 + ReactDOMClient.hydrateRoot(container, <App hasB={false} />, {
657 onRecoverableError(error) {
658 Scheduler.unstable_yieldValue(error.message);
659 },
@@ -709,7 +711,7 @@ describe('ReactDOMServerPartialHydration', () => {
711 // On the client we don't have all data yet but we want to start
712 // hydrating anyway.
713 suspend = true;
712 - const root = ReactDOM.hydrateRoot(container, <App />, {
714 + const root = ReactDOMClient.hydrateRoot(container, <App />, {
715 onDeleted(node) {
716 deleted.push(node);
717 },
@@ -770,7 +772,7 @@ describe('ReactDOMServerPartialHydration', () => {
772 }).toErrorDev(
773 'Warning: Cannot hydrate Suspense in legacy mode. Switch from ' +
774 'ReactDOM.hydrate(element, container) to ' +
773 - 'ReactDOM.hydrateRoot(container, <App />)' +
775 + 'ReactDOMClient.hydrateRoot(container, <App />)' +
776 '.render(element) or remove the Suspense components from the server ' +
777 'rendered components.' +
778 '\n in Suspense (at **)' +
@@ -850,7 +852,7 @@ describe('ReactDOMServerPartialHydration', () => {
852 suspend = true;
853
854 act(() => {
853 - ReactDOM.hydrateRoot(container, <App />);
855 + ReactDOMClient.hydrateRoot(container, <App />);
856 });
857
858 expect(container.firstChild.firstChild.tagName).not.toBe('DIV');
@@ -906,7 +908,7 @@ describe('ReactDOMServerPartialHydration', () => {
908 // hydrating anyway.
909 suspend = true;
910 act(() => {
909 - ReactDOM.hydrateRoot(container, <App />);
911 + ReactDOMClient.hydrateRoot(container, <App />);
912 });
913
914 expect(container.firstChild.children[1].textContent).toBe('Middle');
@@ -955,7 +957,7 @@ describe('ReactDOMServerPartialHydration', () => {
957 // On the client we don't have all data yet but we want to start
958 // hydrating anyway.
959 suspend = true;
958 - const root = ReactDOM.hydrateRoot(
960 + const root = ReactDOMClient.hydrateRoot(
961 container,
962 <App text="Hello" className="hello" />,
963 );
@@ -1029,7 +1031,7 @@ describe('ReactDOMServerPartialHydration', () => {
1031 // On the client we don't have all data yet but we want to start
1032 // hydrating anyway.
1033 suspend = true;
1032 - const root = ReactDOM.hydrateRoot(
1034 + const root = ReactDOMClient.hydrateRoot(
1035 container,
1036 <App text="Hello" className="hello" />,
1037 );
@@ -1102,7 +1104,7 @@ describe('ReactDOMServerPartialHydration', () => {
1104 // On the client we don't have all data yet but we want to start
1105 // hydrating anyway.
1106 suspend = true;
1105 - const root = ReactDOM.hydrateRoot(
1107 + const root = ReactDOMClient.hydrateRoot(
1108 container,
1109 <App text="Hello" className="hello" />,
1110 {
@@ -1188,7 +1190,7 @@ describe('ReactDOMServerPartialHydration', () => {
1190 // On the client we don't have all data yet but we want to start
1191 // hydrating anyway.
1192 suspend = true;
1191 - const root = ReactDOM.hydrateRoot(
1193 + const root = ReactDOMClient.hydrateRoot(
1194 container,
1195 <App text="Hello" className="hello" />,
1196 {
@@ -1273,7 +1275,7 @@ describe('ReactDOMServerPartialHydration', () => {
1275 // On the client we don't have all data yet but we want to start
1276 // hydrating anyway.
1277 suspend = true;
1276 - const root = ReactDOM.hydrateRoot(
1278 + const root = ReactDOMClient.hydrateRoot(
1279 container,
1280 <App text="Hello" className="hello" />,
1281 {
@@ -1357,7 +1359,7 @@ describe('ReactDOMServerPartialHydration', () => {
1359 // On the client we don't have all data yet but we want to start
1360 // hydrating anyway.
1361 suspend = true;
1360 - const root = ReactDOM.hydrateRoot(
1362 + const root = ReactDOMClient.hydrateRoot(
1363 container,
1364 <App text="Hello" className="hello" />,
1365 );
@@ -1439,7 +1441,10 @@ describe('ReactDOMServerPartialHydration', () => {
1441 const container = document.createElement('div');
1442 container.innerHTML = finalHTML;
1443
1442 - ReactDOM.hydrateRoot(container, <App text="Hello" className="hello" />);
1444 + ReactDOMClient.hydrateRoot(
1445 + container,
1446 + <App text="Hello" className="hello" />,
1447 + );
1448
1449 await act(async () => {
1450 suspend = true;
@@ -1509,7 +1514,7 @@ describe('ReactDOMServerPartialHydration', () => {
1514 // On the client we don't have all data yet but we want to start
1515 // hydrating anyway.
1516 suspend = true;
1512 - const root = ReactDOM.hydrateRoot(
1517 + const root = ReactDOMClient.hydrateRoot(
1518 container,
1519 <Context.Provider value={{text: 'Hello', className: 'hello'}}>
1520 <App />
@@ -1591,7 +1596,7 @@ describe('ReactDOMServerPartialHydration', () => {
1596 // On the client we don't have all data yet but we want to start
1597 // hydrating anyway.
1598 suspend = true;
1594 - const root = ReactDOM.hydrateRoot(
1599 + const root = ReactDOMClient.hydrateRoot(
1600 container,
1601 <Context.Provider value={{text: 'Hello', className: 'hello'}}>
1602 <App />
@@ -1680,7 +1685,7 @@ describe('ReactDOMServerPartialHydration', () => {
1685
1686 // On the client we have the data available quickly for some reason.
1687 suspend = false;
1683 - ReactDOM.hydrateRoot(container, <App />, {
1688 + ReactDOMClient.hydrateRoot(container, <App />, {
1689 onRecoverableError(error) {
1690 Scheduler.unstable_yieldValue(error.message);
1691 },
@@ -1742,7 +1747,7 @@ describe('ReactDOMServerPartialHydration', () => {
1747
1748 // On the client we have the data available quickly for some reason.
1749 suspend = false;
1745 - ReactDOM.hydrateRoot(container, <App />, {
1750 + ReactDOMClient.hydrateRoot(container, <App />, {
1751 onRecoverableError(error) {
1752 Scheduler.unstable_yieldValue(error.message);
1753 },
@@ -1809,7 +1814,7 @@ describe('ReactDOMServerPartialHydration', () => {
1814
1815 // On the client we have the data available quickly for some reason.
1816 suspend = false;
1812 - ReactDOM.hydrateRoot(container, <App />, {
1817 + ReactDOMClient.hydrateRoot(container, <App />, {
1818 onRecoverableError(error) {
1819 Scheduler.unstable_yieldValue(error.message);
1820 },
@@ -1882,7 +1887,10 @@ describe('ReactDOMServerPartialHydration', () => {
1887
1888 const spanB = container.getElementsByTagName('span')[1];
1889
1885 - const root = ReactDOM.hydrateRoot(container, <App showMore={false} />);
1890 + const root = ReactDOMClient.hydrateRoot(
1891 + container,
1892 + <App showMore={false} />,
1893 + );
1894 suspend = true;
1895 Scheduler.unstable_flushAll();
1896
@@ -1962,7 +1970,10 @@ describe('ReactDOMServerPartialHydration', () => {
1970
1971 const spanA = container.getElementsByTagName('span')[0];
1972
1965 - const root = ReactDOM.hydrateRoot(container, <App showMore={false} />);
1973 + const root = ReactDOMClient.hydrateRoot(
1974 + container,
1975 + <App showMore={false} />,
1976 + );
1977
1978 suspend = true;
1979 Scheduler.unstable_flushAll();
@@ -2048,7 +2059,7 @@ describe('ReactDOMServerPartialHydration', () => {
2059 const b = container.getElementsByTagName('span')[1];
2060 expect(b.textContent).toBe('B');
2061
2051 - const root = ReactDOM.hydrateRoot(container, <App />);
2062 + const root = ReactDOMClient.hydrateRoot(container, <App />);
2063
2064 // Increase hydration priority to higher than "offscreen".
2065 root.unstable_scheduleHydration(b);
@@ -2119,7 +2130,7 @@ describe('ReactDOMServerPartialHydration', () => {
2130 const container = document.createElement('div');
2131 container.innerHTML = html;
2132
2122 - ReactDOM.hydrateRoot(container, <App />, {
2133 + ReactDOMClient.hydrateRoot(container, <App />, {
2134 onRecoverableError(error) {
2135 Scheduler.unstable_yieldValue(error.message);
2136 },
@@ -2184,7 +2195,7 @@ describe('ReactDOMServerPartialHydration', () => {
2195 const span = container.getElementsByTagName('span')[1];
2196
2197 suspend = false;
2187 - ReactDOM.hydrateRoot(container, <App />, {
2198 + ReactDOMClient.hydrateRoot(container, <App />, {
2199 onRecoverableError(error) {
2200 Scheduler.unstable_yieldValue(error.message);
2201 },
@@ -2233,7 +2244,7 @@ describe('ReactDOMServerPartialHydration', () => {
2244
2245 // On the client we don't have all data yet but we want to start
2246 // hydrating anyway.
2236 - ReactDOM.hydrateRoot(container, <App />);
2247 + ReactDOMClient.hydrateRoot(container, <App />);
2248 Scheduler.unstable_flushAll();
2249 jest.runAllTimers();
2250
@@ -2285,7 +2296,7 @@ describe('ReactDOMServerPartialHydration', () => {
2296 // On the client we don't have all data yet but we want to start
2297 // hydrating anyway.
2298 suspend = true;
2288 - const root = ReactDOM.hydrateRoot(
2299 + const root = ReactDOMClient.hydrateRoot(
2300 container,
2301 <ClassName.Provider value={'hello'}>
2302 <App text="Hello" />
@@ -2388,7 +2399,7 @@ describe('ReactDOMServerPartialHydration', () => {
2399 // On the client we don't have all data yet but we want to start
2400 // hydrating anyway.
2401 suspend = true;
2391 - ReactDOM.hydrateRoot(container, <App />);
2402 + ReactDOMClient.hydrateRoot(container, <App />);
2403 Scheduler.unstable_flushAll();
2404 jest.runAllTimers();
2405
@@ -2475,7 +2486,7 @@ describe('ReactDOMServerPartialHydration', () => {
2486 // hydrating anyway.
2487 suspend = true;
2488 isServerRendering = false;
2478 - ReactDOM.hydrateRoot(container, <App />);
2489 + ReactDOMClient.hydrateRoot(container, <App />);
2490
2491 // We'll do one click before hydrating.
2492 a.click();
@@ -2565,7 +2576,7 @@ describe('ReactDOMServerPartialHydration', () => {
2576 // On the client we don't have all data yet but we want to start
2577 // hydrating anyway.
2578 suspend = true;
2568 - ReactDOM.hydrateRoot(container, <App />);
2579 + ReactDOMClient.hydrateRoot(container, <App />);
2580
2581 // We'll do one click before hydrating.
2582 await act(async () => {
@@ -2660,7 +2671,7 @@ describe('ReactDOMServerPartialHydration', () => {
2671 // hydrating anyway.
2672 suspend = true;
2673 isServerRendering = false;
2663 - ReactDOM.hydrateRoot(container, <App />);
2674 + ReactDOMClient.hydrateRoot(container, <App />);
2675
2676 // We'll do one click before hydrating.
2677 a.click();
@@ -2747,7 +2758,7 @@ describe('ReactDOMServerPartialHydration', () => {
2758 // On the client we don't have all data yet but we want to start
2759 // hydrating anyway.
2760 suspend = true;
2750 - ReactDOM.hydrateRoot(container, <App />);
2761 + ReactDOMClient.hydrateRoot(container, <App />);
2762 Scheduler.unstable_flushAll();
2763 jest.runAllTimers();
2764
@@ -2822,7 +2833,7 @@ describe('ReactDOMServerPartialHydration', () => {
2833
2834 // We're going to use a different root as a parent.
2835 // This lets us detect whether an event goes through React's event system.
2825 - const parentRoot = ReactDOM.createRoot(parentContainer);
2836 + const parentRoot = ReactDOMClient.createRoot(parentContainer);
2837 parentRoot.render(<Parent />);
2838 Scheduler.unstable_flushAll();
2839
@@ -2835,7 +2846,7 @@ describe('ReactDOMServerPartialHydration', () => {
2846 suspend = true;
2847
2848 // Hydrate asynchronously.
2838 - ReactDOM.hydrateRoot(childContainer, <App />);
2849 + ReactDOMClient.hydrateRoot(childContainer, <App />);
2850 jest.runAllTimers();
2851 Scheduler.unstable_flushAll();
2852
@@ -2933,7 +2944,7 @@ describe('ReactDOMServerPartialHydration', () => {
2944 // hydrating anyway.
2945 suspend1 = true;
2946 suspend2 = true;
2936 - ReactDOM.hydrateRoot(container, <App />);
2947 + ReactDOMClient.hydrateRoot(container, <App />);
2948
2949 Scheduler.unstable_flushAll();
2950 jest.runAllTimers();
@@ -3019,7 +3030,10 @@ describe('ReactDOMServerPartialHydration', () => {
3030 container.innerHTML = finalHTML;
3031
3032 suspend = true;
3022 - const root = ReactDOM.hydrateRoot(container, <App showSibling={false} />);
3033 + const root = ReactDOMClient.hydrateRoot(
3034 + container,
3035 + <App showSibling={false} />,
3036 + );
3037 expect(Scheduler).toFlushAndYield([]);
3038
3039 expect(ref.current).toBe(null);
@@ -3105,7 +3119,7 @@ describe('ReactDOMServerPartialHydration', () => {
3119 // On the client we don't have all data yet but we want to start
3120 // hydrating anyway.
3121 suspend = true;
3108 - ReactDOM.hydrateRoot(container, <App />);
3122 + ReactDOMClient.hydrateRoot(container, <App />);
3123 Scheduler.unstable_flushAll();
3124 jest.runAllTimers();
3125
@@ -3170,7 +3184,7 @@ describe('ReactDOMServerPartialHydration', () => {
3184 const span = container.getElementsByTagName('span')[0];
3185 expect(span.innerHTML).toBe('Hidden child');
3186
3173 - ReactDOM.hydrateRoot(container, <App />, {
3187 + ReactDOMClient.hydrateRoot(container, <App />, {
3188 onRecoverableError(error) {
3189 Scheduler.unstable_yieldValue(
3190 'Log recoverable error: ' + error.message,
@@ -3205,7 +3219,7 @@ describe('ReactDOMServerPartialHydration', () => {
3219 const span = container.getElementsByTagName('span')[0];
3220 expect(span.innerHTML).toBe('Hidden child');
3221
3208 - ReactDOM.hydrateRoot(container, <App />);
3222 + ReactDOMClient.hydrateRoot(container, <App />);
3223 Scheduler.unstable_flushAll();
3224 expect(ref.current).toBe(span);
3225 expect(span.innerHTML).toBe('Hidden child');
@@ -3230,7 +3244,7 @@ describe('ReactDOMServerPartialHydration', () => {
3244
3245 const span = container.getElementsByTagName('span')[0];
3246
3233 - ReactDOM.hydrateRoot(container, <App />);
3247 + ReactDOMClient.hydrateRoot(container, <App />);
3248 Scheduler.unstable_flushAll();
3249 expect(ref.current).toBe(span);
3250 expect(ref.current.innerHTML).toBe('Hidden child');
@@ -3243,7 +3257,7 @@ describe('ReactDOMServerPartialHydration', () => {
3257 const finalHTML = ReactDOMServer.renderToString(<App />);
3258 container.innerHTML = finalHTML;
3259
3246 - ReactDOM.hydrateRoot(container, <App />);
3260 + ReactDOMClient.hydrateRoot(container, <App />);
3261 Scheduler.unstable_flushAll();
3262 });
3263 }
@@ -3321,7 +3335,7 @@ describe('ReactDOMServerPartialHydration', () => {
3335
3336 expect(() => {
3337 act(() => {
3324 - ReactDOM.hydrateRoot(container, <App />, {
3338 + ReactDOMClient.hydrateRoot(container, <App />, {
3339 onRecoverableError(error) {
3340 Scheduler.unstable_yieldValue(
3341 'Log recoverable error: ' + error.message,
@@ -3373,7 +3387,7 @@ describe('ReactDOMServerPartialHydration', () => {
3387 );
3388 expect(() => {
3389 act(() => {
3376 - ReactDOM.hydrateRoot(container, <DirectTextChild text="bad" />, {
3390 + ReactDOMClient.hydrateRoot(container, <DirectTextChild text="bad" />, {
3391 onRecoverableError(error) {
3392 Scheduler.unstable_yieldValue(error.message);
3393 },
@@ -3414,11 +3428,15 @@ describe('ReactDOMServerPartialHydration', () => {
3428 );
3429 expect(() => {
3430 act(() => {
3417 - ReactDOM.hydrateRoot(container2, <TextChildWithSibling text="bad" />, {
3418 - onRecoverableError(error) {
3419 - Scheduler.unstable_yieldValue(error.message);
3431 + ReactDOMClient.hydrateRoot(
3432 + container2,
3433 + <TextChildWithSibling text="bad" />,
3434 + {
3435 + onRecoverableError(error) {
3436 + Scheduler.unstable_yieldValue(error.message);
3437 + },
3438 },
3421 - });
3439 + );
3440 });
3441 }).toErrorDev(
3442 [
packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js
+23 -21
@@ -13,6 +13,7 @@ import {createEventTarget} from 'dom-event-testing-library';
13
14 let React;
15 let ReactDOM;
16 +let ReactDOMClient;
17 let ReactDOMServer;
18 let ReactFeatureFlags;
19 let Scheduler;
@@ -117,6 +118,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
118 ReactFeatureFlags.enableCreateEventHandleAPI = true;
119 React = require('react');
120 ReactDOM = require('react-dom');
121 + ReactDOMClient = require('react-dom/client');
122 ReactDOMServer = require('react-dom/server');
123 act = require('jest-react').act;
124 Scheduler = require('scheduler');
@@ -165,7 +167,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
167
168 const span = container.getElementsByTagName('span')[1];
169
168 - ReactDOM.hydrateRoot(container, <App />);
170 + ReactDOMClient.hydrateRoot(container, <App />);
171
172 // Nothing has been hydrated so far.
173 expect(Scheduler).toHaveYielded([]);
@@ -243,7 +245,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
245
246 // A and D will be suspended. We'll click on D which should take
247 // priority, after we unsuspend.
246 - ReactDOM.hydrateRoot(container, <App />);
248 + ReactDOMClient.hydrateRoot(container, <App />);
249
250 // Nothing has been hydrated so far.
251 expect(Scheduler).toHaveYielded([]);
@@ -341,7 +343,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
343
344 // A and D will be suspended. We'll click on D which should take
345 // priority, after we unsuspend.
344 - ReactDOM.hydrateRoot(container, <App />);
346 + ReactDOMClient.hydrateRoot(container, <App />);
347
348 // Nothing has been hydrated so far.
349 expect(Scheduler).toHaveYielded([]);
@@ -440,7 +442,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
442
443 isServerRendering = false;
444
443 - ReactDOM.hydrateRoot(container, <App />);
445 + ReactDOMClient.hydrateRoot(container, <App />);
446
447 // Nothing has been hydrated so far.
448 expect(Scheduler).toHaveYielded([]);
@@ -525,7 +527,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
527
528 // A and D will be suspended. We'll click on D which should take
529 // priority, after we unsuspend.
528 - ReactDOM.hydrateRoot(container, <App />);
530 + ReactDOMClient.hydrateRoot(container, <App />);
531
532 // Nothing has been hydrated so far.
533 expect(Scheduler).toHaveYielded([]);
@@ -623,7 +625,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
625
626 // A and D will be suspended. We'll click on D which should take
627 // priority, after we unsuspend.
626 - ReactDOM.hydrateRoot(container, <App />);
628 + ReactDOMClient.hydrateRoot(container, <App />);
629
630 // Nothing has been hydrated so far.
631 expect(Scheduler).toHaveYielded([]);
@@ -732,7 +734,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
734
735 // A and D will be suspended. We'll click on D which should take
736 // priority, after we unsuspend.
735 - ReactDOM.hydrateRoot(container, <App />);
737 + ReactDOMClient.hydrateRoot(container, <App />);
738
739 // Nothing has been hydrated so far.
740 expect(Scheduler).toHaveYielded([]);
@@ -882,7 +884,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
884
885 // A and D will be suspended. We'll click on D which should take
886 // priority, after we unsuspend.
885 - ReactDOM.hydrateRoot(container, <App />);
887 + ReactDOMClient.hydrateRoot(container, <App />);
888
889 // Nothing has been hydrated so far.
890 expect(Scheduler).toHaveYielded([]);
@@ -974,18 +976,18 @@ describe('ReactDOMServerSelectiveHydration', () => {
976 beforeEach(async () => {
977 document.body.innerHTML = '';
978 jest.resetModuleRegistry();
977 - let OuterReactDOM;
978 - let InnerReactDOM;
979 + let OuterReactDOMClient;
980 + let InnerReactDOMClient;
981 jest.isolateModules(() => {
980 - OuterReactDOM = require('react-dom');
982 + OuterReactDOMClient = require('react-dom/client');
983 OuterScheduler = require('scheduler');
984 });
985 jest.isolateModules(() => {
984 - InnerReactDOM = require('react-dom');
986 + InnerReactDOMClient = require('react-dom/client');
987 InnerScheduler = require('scheduler');
988 });
989
988 - expect(OuterReactDOM).not.toBe(InnerReactDOM);
990 + expect(OuterReactDOMClient).not.toBe(InnerReactDOMClient);
991 expect(OuterScheduler).not.toBe(InnerScheduler);
992
993 const outerContainer = document.createElement('div');
@@ -1071,8 +1073,8 @@ describe('ReactDOMServerSelectiveHydration', () => {
1073 suspendOuter = true;
1074 suspendInner = true;
1075
1074 - OuterReactDOM.hydrateRoot(outerContainer, <OuterApp />);
1075 - InnerReactDOM.hydrateRoot(innerContainer, <InnerApp />);
1076 + OuterReactDOMClient.hydrateRoot(outerContainer, <OuterApp />);
1077 + InnerReactDOMClient.hydrateRoot(innerContainer, <InnerApp />);
1078
1079 expect(OuterScheduler).toFlushAndYield(['Suspend Outer']);
1080 expect(InnerScheduler).toFlushAndYield(['Suspend Inner']);
@@ -1271,7 +1273,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
1273 container.innerHTML = finalHTML;
1274 suspend = true;
1275
1274 - ReactDOM.hydrateRoot(container, <App />);
1276 + ReactDOMClient.hydrateRoot(container, <App />);
1277
1278 const childDiv = container.firstElementChild;
1279 dispatchMouseHoverEvent(childDiv);
@@ -1365,7 +1367,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
1367
1368 // A and D will be suspended. We'll click on D which should take
1369 // priority, after we unsuspend.
1368 - ReactDOM.hydrateRoot(container, <App />);
1370 + ReactDOMClient.hydrateRoot(container, <App />);
1371
1372 // Nothing has been hydrated so far.
1373 expect(Scheduler).toHaveYielded([]);
@@ -1423,7 +1425,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
1425 const spanB = container.getElementsByTagName('span')[1];
1426 const spanC = container.getElementsByTagName('span')[2];
1427
1426 - const root = ReactDOM.hydrateRoot(container, <App />);
1428 + const root = ReactDOMClient.hydrateRoot(container, <App />);
1429
1430 // Nothing has been hydrated so far.
1431 expect(Scheduler).toHaveYielded([]);
@@ -1481,7 +1483,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
1483 const spanC = container.getElementsByTagName('span')[4];
1484
1485 act(() => {
1484 - const root = ReactDOM.hydrateRoot(container, <App a="A" />);
1486 + const root = ReactDOMClient.hydrateRoot(container, <App a="A" />);
1487 // Hydrate the shell.
1488 expect(Scheduler).toFlushAndYieldThrough(['App', 'Commit']);
1489
@@ -1607,7 +1609,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
1609
1610 const span = container.getElementsByTagName('span')[1];
1611
1610 - ReactDOM.hydrateRoot(container, <App />);
1612 + ReactDOMClient.hydrateRoot(container, <App />);
1613
1614 // Nothing has been hydrated so far.
1615 expect(Scheduler).toHaveYielded([]);
@@ -1679,7 +1681,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
1681
1682 suspend = true;
1683
1682 - ReactDOM.hydrateRoot(container, <App />);
1684 + ReactDOMClient.hydrateRoot(container, <App />);
1685 // Nothing has been hydrated so far.
1686 expect(Scheduler).toHaveYielded([]);
1687
packages/react-dom/src/__tests__/ReactDOMServerSuspense-test.internal.js
+3 -1
@@ -13,6 +13,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
13
14 let React;
15 let ReactDOM;
16 +let ReactDOMClient;
17 let ReactDOMServer;
18 let ReactTestUtils;
19 let act;
@@ -24,6 +25,7 @@ function initModules() {
25
26 React = require('react');
27 ReactDOM = require('react-dom');
28 + ReactDOMClient = require('react-dom/client');
29 ReactDOMServer = require('react-dom/server');
30 ReactTestUtils = require('react-dom/test-utils');
31 act = require('jest-react').act;
@@ -163,7 +165,7 @@ describe('ReactDOMServerSuspense', () => {
165 expect(divB.textContent).toBe('B');
166
167 act(() => {
166 - ReactDOM.hydrateRoot(parent, example);
168 + ReactDOMClient.hydrateRoot(parent, example);
169 });
170
171 const parent2 = element.parentNode;
packages/react-dom/src/__tests__/ReactDOMUseId-test.js
+13 -13
@@ -9,7 +9,7 @@
9
10 let JSDOM;
11 let React;
12 -let ReactDOM;
12 +let ReactDOMClient;
13 let Scheduler;
14 let clientAct;
15 let ReactDOMFizzServer;
@@ -29,7 +29,7 @@ describe('useId', () => {
29 jest.resetModules();
30 JSDOM = require('jsdom').JSDOM;
31 React = require('react');
32 - ReactDOM = require('react-dom');
32 + ReactDOMClient = require('react-dom/client');
33 Scheduler = require('scheduler');
34 clientAct = require('jest-react').act;
35 ReactDOMFizzServer = require('react-dom/server');
@@ -136,7 +136,7 @@ describe('useId', () => {
136 pipe(writable);
137 });
138 await clientAct(async () => {
139 - ReactDOM.hydrateRoot(container, <App />);
139 + ReactDOMClient.hydrateRoot(container, <App />);
140 });
141 expect(container).toMatchInlineSnapshot(`
142 <div
@@ -181,7 +181,7 @@ describe('useId', () => {
181 pipe(writable);
182 });
183 await clientAct(async () => {
184 - ReactDOM.hydrateRoot(container, <App />);
184 + ReactDOMClient.hydrateRoot(container, <App />);
185 });
186 expect(container).toMatchInlineSnapshot(`
187 <div
@@ -220,7 +220,7 @@ describe('useId', () => {
220 pipe(writable);
221 });
222 await clientAct(async () => {
223 - ReactDOM.hydrateRoot(container, <App />);
223 + ReactDOMClient.hydrateRoot(container, <App />);
224 });
225 expect(container).toMatchInlineSnapshot(`
226 <div
@@ -256,7 +256,7 @@ describe('useId', () => {
256 pipe(writable);
257 });
258 await clientAct(async () => {
259 - ReactDOM.hydrateRoot(container, <App />);
259 + ReactDOMClient.hydrateRoot(container, <App />);
260 });
261 expect(container).toMatchInlineSnapshot(`
262 <div
@@ -311,7 +311,7 @@ describe('useId', () => {
311 pipe(writable);
312 });
313 await clientAct(async () => {
314 - ReactDOM.hydrateRoot(container, <App />);
314 + ReactDOMClient.hydrateRoot(container, <App />);
315 });
316 const divs = container.querySelectorAll('div');
317
@@ -335,7 +335,7 @@ describe('useId', () => {
335 pipe(writable);
336 });
337 await clientAct(async () => {
338 - ReactDOM.hydrateRoot(container, <App />);
338 + ReactDOMClient.hydrateRoot(container, <App />);
339 });
340 // We append a suffix to the end of the id to distinguish them
341 expect(container).toMatchInlineSnapshot(`
@@ -362,7 +362,7 @@ describe('useId', () => {
362 pipe(writable);
363 });
364 await clientAct(async () => {
365 - ReactDOM.hydrateRoot(container, <App />);
365 + ReactDOMClient.hydrateRoot(container, <App />);
366 });
367 expect(container).toMatchInlineSnapshot(`
368 <div
@@ -392,7 +392,7 @@ describe('useId', () => {
392 pipe(writable);
393 });
394 await clientAct(async () => {
395 - ReactDOM.hydrateRoot(container, <App />);
395 + ReactDOMClient.hydrateRoot(container, <App />);
396 });
397 expect(container).toMatchInlineSnapshot(`
398 <div
@@ -443,7 +443,7 @@ describe('useId', () => {
443 });
444 const dehydratedSpan = container.getElementsByTagName('span')[0];
445 await clientAct(async () => {
446 - const root = ReactDOM.hydrateRoot(container, <App />);
446 + const root = ReactDOMClient.hydrateRoot(container, <App />);
447 expect(Scheduler).toFlushUntilNextPaint([]);
448 expect(container).toMatchInlineSnapshot(`
449 <div
@@ -524,7 +524,7 @@ describe('useId', () => {
524 });
525 const dehydratedSpan = container.getElementsByTagName('span')[0];
526 await clientAct(async () => {
527 - const root = ReactDOM.hydrateRoot(container, <App />);
527 + const root = ReactDOMClient.hydrateRoot(container, <App />);
528 expect(Scheduler).toFlushUntilNextPaint([]);
529 expect(container).toMatchInlineSnapshot(`
530 <div
@@ -598,7 +598,7 @@ describe('useId', () => {
598 });
599 let root;
600 await clientAct(async () => {
601 - root = ReactDOM.hydrateRoot(container, <App />, {
601 + root = ReactDOMClient.hydrateRoot(container, <App />, {
602 identifierPrefix: 'custom-prefix-',
603 });
604 });
packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js
+3 -1
@@ -11,6 +11,7 @@
11
12 let React;
13 let ReactDOM;
14 +let ReactDOMClient;
15 let ReactDOMServer;
16 let Scheduler;
17
@@ -21,6 +22,7 @@ describe('ReactDOMServerHydration', () => {
22 jest.resetModules();
23 React = require('react');
24 ReactDOM = require('react-dom');
25 + ReactDOMClient = require('react-dom/client');
26 ReactDOMServer = require('react-dom/server');
27 Scheduler = require('scheduler');
28 });
@@ -403,7 +405,7 @@ describe('ReactDOMServerHydration', () => {
405 const finalHTML = ReactDOMServer.renderToString(<div />);
406 const container = document.createElement('div');
407 container.innerHTML = finalHTML;
406 - const root = ReactDOM.hydrateRoot(container, <div />);
408 + const root = ReactDOMClient.hydrateRoot(container, <div />);
409 Scheduler.unstable_flushAll();
410 root.render(null);
411 Scheduler.unstable_flushAll();
packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js
+4 -2
@@ -9,6 +9,7 @@
9
10 let React;
11 let ReactDOM;
12 +let ReactDOMClient;
13 let ReactTestUtils;
14 let Scheduler;
15 let act;
@@ -31,7 +32,7 @@ describe('ReactTestUtils.act()', () => {
32 if (__EXPERIMENTAL__) {
33 let concurrentRoot = null;
34 const renderConcurrent = (el, dom) => {
34 - concurrentRoot = ReactDOM.createRoot(dom);
35 + concurrentRoot = ReactDOMClient.createRoot(dom);
36 if (__DEV__) {
37 act(() => concurrentRoot.render(el));
38 } else {
@@ -100,7 +101,7 @@ describe('ReactTestUtils.act()', () => {
101
102 // @gate __DEV__
103 it('does not warn in concurrent mode', () => {
103 - const root = ReactDOM.createRoot(document.createElement('div'));
104 + const root = ReactDOMClient.createRoot(document.createElement('div'));
105 act(() => root.render(<App />));
106 Scheduler.unstable_flushAll();
107 });
@@ -113,6 +114,7 @@ function runActTests(label, render, unmount, rerender) {
114 jest.resetModules();
115 React = require('react');
116 ReactDOM = require('react-dom');
117 + ReactDOMClient = require('react-dom/client');
118 ReactTestUtils = require('react-dom/test-utils');
119 Scheduler = require('scheduler');
120 act = ReactTestUtils.act;
packages/react-dom/src/__tests__/ReactUpdates-test.js
+4 -2
@@ -11,6 +11,7 @@
11
12 let React;
13 let ReactDOM;
14 +let ReactDOMClient;
15 let ReactTestUtils;
16 let act;
17 let Scheduler;
@@ -20,6 +21,7 @@ describe('ReactUpdates', () => {
21 jest.resetModules();
22 React = require('react');
23 ReactDOM = require('react-dom');
24 + ReactDOMClient = require('react-dom/client');
25 ReactTestUtils = require('react-dom/test-utils');
26 act = require('jest-react').act;
27 Scheduler = require('scheduler');
@@ -1332,7 +1334,7 @@ describe('ReactUpdates', () => {
1334 );
1335 }
1336
1335 - const root = ReactDOM.createRoot(container);
1337 + const root = ReactDOMClient.createRoot(container);
1338 let hiddenDiv;
1339 act(() => {
1340 root.render(<Foo />);
@@ -1709,7 +1711,7 @@ describe('ReactUpdates', () => {
1711 }
1712
1713 const container = document.createElement('div');
1712 - const root = ReactDOM.createRoot(container);
1714 + const root = ReactDOMClient.createRoot(container);
1715 expect(() => {
1716 ReactDOM.flushSync(() => {
1717 root.render(<NonTerminating />);
packages/react-dom/src/client/ReactDOM.js
+42 -1
@@ -9,6 +9,11 @@
9
10 import type {ReactNodeList} from 'shared/ReactTypes';
11 import type {Container} from './ReactDOMHostConfig';
12 +import type {
13 + RootType,
14 + HydrateRootOptions,
15 + CreateRootOptions,
16 +} from './ReactDOMRoot';
17
18 import {
19 findDOMNode,
@@ -17,7 +22,11 @@ import {
22 unstable_renderSubtreeIntoContainer,
23 unmountComponentAtNode,
24 } from './ReactDOMLegacy';
20 -import {createRoot, hydrateRoot, isValidContainer} from './ReactDOMRoot';
25 +import {
26 + createRoot as createRootImpl,
27 + hydrateRoot as hydrateRootImpl,
28 + isValidContainer,
29 +} from './ReactDOMRoot';
30 import {createEventHandle} from './ReactDOMEventHandle';
31
32 import {
@@ -125,6 +134,7 @@ function renderSubtreeIntoContainer(
134 }
135
136 const Internals = {
137 + usingClientEntryPoint: false,
138 // Keep in sync with ReactTestUtils.js.
139 // This is an array for better minification.
140 Events: [
@@ -137,6 +147,37 @@ const Internals = {
147 ],
148 };
149
150 +function createRoot(
151 + container: Container,
152 + options?: CreateRootOptions,
153 +): RootType {
154 + if (__DEV__) {
155 + if (!Internals.usingClientEntryPoint) {
156 + console.error(
157 + 'You are importing createRoot from "react-dom" which is not supported. ' +
158 + 'You should instead import it from "react-dom/client".',
159 + );
160 + }
161 + }
162 + return createRootImpl(container, options);
163 +}
164 +
165 +function hydrateRoot(
166 + container: Container,
167 + initialChildren: ReactNodeList,
168 + options?: HydrateRootOptions,
169 +): RootType {
170 + if (__DEV__) {
171 + if (!Internals.usingClientEntryPoint) {
172 + console.error(
173 + 'You are importing hydrateRoot from "react-dom" which is not supported. ' +
174 + 'You should instead import it from "react-dom/client".',
175 + );
176 + }
177 + }
178 + return hydrateRootImpl(container, initialChildren, options);
179 +}
180 +
181 // Overload the definition to the two valid signatures.
182 // Warning, this opts-out of checking the function body.
183 declare function flushSync<R>(fn: () => R): R;
packages/react-dom/src/client/ReactDOMLegacy.js
+3 -3
@@ -256,7 +256,7 @@ export function hydrate(
256 if (isModernRoot) {
257 console.error(
258 'You are calling ReactDOM.hydrate() on a container that was previously ' +
259 - 'passed to ReactDOM.createRoot(). This is not supported. ' +
259 + 'passed to ReactDOMClient.createRoot(). This is not supported. ' +
260 'Did you mean to call hydrateRoot(container, element)?',
261 );
262 }
@@ -296,7 +296,7 @@ export function render(
296 if (isModernRoot) {
297 console.error(
298 'You are calling ReactDOM.render() on a container that was previously ' +
299 - 'passed to ReactDOM.createRoot(). This is not supported. ' +
299 + 'passed to ReactDOMClient.createRoot(). This is not supported. ' +
300 'Did you mean to call root.render(element)?',
301 );
302 }
@@ -356,7 +356,7 @@ export function unmountComponentAtNode(container: Container) {
356 if (isModernRoot) {
357 console.error(
358 'You are calling ReactDOM.unmountComponentAtNode() on a container that was previously ' +
359 - 'passed to ReactDOM.createRoot(). This is not supported. Did you mean to call root.unmount()?',
359 + 'passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.unmount()?',
360 );
361 }
362 }
packages/react-dom/src/client/ReactDOMRoot.js
+3 -3
@@ -184,7 +184,7 @@ export function createRoot(
184 if (__DEV__) {
185 if ((options: any).hydrate) {
186 console.warn(
187 - 'hydrate through createRoot is deprecated. Use ReactDOM.hydrateRoot(container, <App />) instead.',
187 + 'hydrate through createRoot is deprecated. Use ReactDOMClient.hydrateRoot(container, <App />) instead.',
188 );
189 } else {
190 if (
@@ -369,12 +369,12 @@ function warnIfReactDOMContainerInDEV(container) {
369 if (isContainerMarkedAsRoot(container)) {
370 if (container._reactRootContainer) {
371 console.error(
372 - 'You are calling ReactDOM.createRoot() on a container that was previously ' +
372 + 'You are calling ReactDOMClient.createRoot() on a container that was previously ' +
373 'passed to ReactDOM.render(). This is not supported.',
374 );
375 } else {
376 console.error(
377 - 'You are calling ReactDOM.createRoot() on a container that ' +
377 + 'You are calling ReactDOMClient.createRoot() on a container that ' +
378 'has already been passed to createRoot() before. Instead, call ' +
379 'root.render() on the existing root instead if you want to update it.',
380 );
packages/react-dom/src/events/__tests__/DOMPluginEventSystem-test.internal.js
+10 -6
@@ -14,6 +14,7 @@ import {createEventTarget} from 'dom-event-testing-library';
14 let React;
15 let ReactFeatureFlags;
16 let ReactDOM;
17 +let ReactDOMClient;
18 let ReactDOMServer;
19 let Scheduler;
20 let act;
@@ -64,6 +65,7 @@ describe('DOMPluginEventSystem', () => {
65
66 React = require('react');
67 ReactDOM = require('react-dom');
68 + ReactDOMClient = require('react-dom/client');
69 Scheduler = require('scheduler');
70 ReactDOMServer = require('react-dom/server');
71 act = require('jest-react').act;
@@ -616,7 +618,7 @@ describe('DOMPluginEventSystem', () => {
618
619 // We're going to use a different root as a parent.
620 // This lets us detect whether an event goes through React's event system.
619 - const parentRoot = ReactDOM.createRoot(parentContainer);
621 + const parentRoot = ReactDOMClient.createRoot(parentContainer);
622 parentRoot.render(<Parent />);
623 Scheduler.unstable_flushAll();
624
@@ -629,7 +631,7 @@ describe('DOMPluginEventSystem', () => {
631 suspend = true;
632
633 // Hydrate asynchronously.
632 - ReactDOM.hydrateRoot(childContainer, <App />);
634 + ReactDOMClient.hydrateRoot(childContainer, <App />);
635 jest.runAllTimers();
636 Scheduler.unstable_flushAll();
637
@@ -1258,6 +1260,7 @@ describe('DOMPluginEventSystem', () => {
1260
1261 React = require('react');
1262 ReactDOM = require('react-dom');
1263 + ReactDOMClient = require('react-dom/client');
1264 Scheduler = require('scheduler');
1265 ReactDOMServer = require('react-dom/server');
1266 act = require('jest-react').act;
@@ -1940,7 +1943,7 @@ describe('DOMPluginEventSystem', () => {
1943 return <button ref={ref}>Press me</button>;
1944 }
1945
1943 - const root = ReactDOM.createRoot(container);
1946 + const root = ReactDOMClient.createRoot(container);
1947 root.render(<Test counter={0} />);
1948
1949 expect(Scheduler).toFlushAndYield(['Test']);
@@ -2561,7 +2564,7 @@ describe('DOMPluginEventSystem', () => {
2564 const container2 = document.createElement('div');
2565 document.body.appendChild(container2);
2566
2564 - const root = ReactDOM.createRoot(container2);
2567 + const root = ReactDOMClient.createRoot(container2);
2568
2569 act(() => {
2570 root.render(<Component />);
@@ -2648,7 +2651,7 @@ describe('DOMPluginEventSystem', () => {
2651 const container2 = document.createElement('div');
2652 document.body.appendChild(container2);
2653
2651 - const root = ReactDOM.createRoot(container2);
2654 + const root = ReactDOMClient.createRoot(container2);
2655
2656 act(() => {
2657 root.render(<Component />);
@@ -2715,7 +2718,7 @@ describe('DOMPluginEventSystem', () => {
2718 const container2 = document.createElement('div');
2719 document.body.appendChild(container2);
2720
2718 - const root = ReactDOM.createRoot(container2);
2721 + const root = ReactDOMClient.createRoot(container2);
2722 act(() => {
2723 root.render(<Component />);
2724 });
@@ -2872,6 +2875,7 @@ describe('DOMPluginEventSystem', () => {
2875
2876 React = require('react');
2877 ReactDOM = require('react-dom');
2878 + ReactDOMClient = require('react-dom/client');
2879 Scheduler = require('scheduler');
2880 ReactDOMServer = require('react-dom/server');
2881 });
packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js
+8 -6
@@ -11,6 +11,7 @@
11
12 let React;
13 let ReactDOM;
14 +let ReactDOMClient;
15 let ReactFeatureFlags;
16 let Scheduler;
17 let act;
@@ -56,6 +57,7 @@ describe('ChangeEventPlugin', () => {
57 };
58 React = require('react');
59 ReactDOM = require('react-dom');
60 + ReactDOMClient = require('react-dom/client');
61 act = require('jest-react').act;
62 Scheduler = require('scheduler');
63 container = document.createElement('div');
@@ -496,7 +498,7 @@ describe('ChangeEventPlugin', () => {
498
499 describe('concurrent mode', () => {
500 it('text input', () => {
499 - const root = ReactDOM.createRoot(container);
501 + const root = ReactDOMClient.createRoot(container);
502 let input;
503
504 class ControlledInput extends React.Component {
@@ -538,7 +540,7 @@ describe('ChangeEventPlugin', () => {
540 });
541
542 it('checkbox input', () => {
541 - const root = ReactDOM.createRoot(container);
543 + const root = ReactDOMClient.createRoot(container);
544 let input;
545
546 class ControlledInput extends React.Component {
@@ -593,7 +595,7 @@ describe('ChangeEventPlugin', () => {
595 });
596
597 it('textarea', () => {
596 - const root = ReactDOM.createRoot(container);
598 + const root = ReactDOMClient.createRoot(container);
599 let textarea;
600
601 class ControlledTextarea extends React.Component {
@@ -635,7 +637,7 @@ describe('ChangeEventPlugin', () => {
637 });
638
639 it('parent of input', () => {
638 - const root = ReactDOM.createRoot(container);
640 + const root = ReactDOMClient.createRoot(container);
641 let input;
642
643 class ControlledInput extends React.Component {
@@ -681,7 +683,7 @@ describe('ChangeEventPlugin', () => {
683 });
684
685 it('is sync for non-input events', async () => {
684 - const root = ReactDOM.createRoot(container);
686 + const root = ReactDOMClient.createRoot(container);
687 let input;
688
689 class ControlledInput extends React.Component {
@@ -729,7 +731,7 @@ describe('ChangeEventPlugin', () => {
731 it('mouse enter/leave should be user-blocking but not discrete', async () => {
732 const {useState} = React;
733
732 - const root = ReactDOM.createRoot(container);
734 + const root = ReactDOMClient.createRoot(container);
735
736 const target = React.createRef(null);
737 function Foo() {
packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js
+5 -2
@@ -12,6 +12,7 @@
12 describe('SimpleEventPlugin', function() {
13 let React;
14 let ReactDOM;
15 + let ReactDOMClient;
16 let Scheduler;
17 let act;
18
@@ -39,6 +40,7 @@ describe('SimpleEventPlugin', function() {
40 jest.resetModules();
41 React = require('react');
42 ReactDOM = require('react-dom');
43 + ReactDOMClient = require('react-dom/client');
44 Scheduler = require('scheduler');
45
46 onClick = jest.fn();
@@ -235,6 +237,7 @@ describe('SimpleEventPlugin', function() {
237
238 React = require('react');
239 ReactDOM = require('react-dom');
240 + ReactDOMClient = require('react-dom/client');
241 Scheduler = require('scheduler');
242
243 act = require('jest-react').act;
@@ -242,7 +245,7 @@ describe('SimpleEventPlugin', function() {
245
246 it('flushes pending interactive work before exiting event handler', async () => {
247 container = document.createElement('div');
245 - const root = ReactDOM.createRoot(container);
248 + const root = ReactDOMClient.createRoot(container);
249 document.body.appendChild(container);
250
251 let button;
@@ -317,7 +320,7 @@ describe('SimpleEventPlugin', function() {
320 // was dispatched.
321 it('end result of many interactive updates is deterministic', async () => {
322 container = document.createElement('div');
320 - const root = ReactDOM.createRoot(container);
323 + const root = ReactDOMClient.createRoot(container);
324 document.body.appendChild(container);
325
326 let button;
packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocusWithin-test.internal.js
+4 -2
@@ -14,6 +14,7 @@ import {createEventTarget, setPointerEvent} from 'dom-event-testing-library';
14 let React;
15 let ReactFeatureFlags;
16 let ReactDOM;
17 +let ReactDOMClient;
18 let useFocusWithin;
19 let act;
20 let Scheduler;
@@ -26,6 +27,7 @@ function initializeModules(hasPointerEvents) {
27 ReactFeatureFlags.enableCreateEventHandleAPI = true;
28 React = require('react');
29 ReactDOM = require('react-dom');
30 + ReactDOMClient = require('react-dom/client');
31 Scheduler = require('scheduler');
32 act = require('jest-react').act;
33
@@ -504,7 +506,7 @@ describe.each(table)(`useFocus`, hasPointerEvents => {
506 );
507 };
508
507 - const root = ReactDOM.createRoot(container2);
509 + const root = ReactDOMClient.createRoot(container2);
510
511 act(() => {
512 root.render(<Component />);
@@ -563,7 +565,7 @@ describe.each(table)(`useFocus`, hasPointerEvents => {
565 );
566 };
567
566 - const root = ReactDOM.createRoot(container2);
568 + const root = ReactDOMClient.createRoot(container2);
569
570 act(() => {
571 root.render(<Component />);
packages/react-reconciler/src/ReactFiberBeginWork.new.js
+1 -1
@@ -2628,7 +2628,7 @@ function mountDehydratedSuspenseComponent(
2628 console.error(
2629 'Cannot hydrate Suspense in legacy mode. Switch from ' +
2630 'ReactDOM.hydrate(element, container) to ' +
2631 - 'ReactDOM.hydrateRoot(container, <App />)' +
2631 + 'ReactDOMClient.hydrateRoot(container, <App />)' +
2632 '.render(element) or remove the Suspense components from ' +
2633 'the server rendered components.',
2634 );
packages/react-reconciler/src/ReactFiberBeginWork.old.js
+1 -1
@@ -2628,7 +2628,7 @@ function mountDehydratedSuspenseComponent(
2628 console.error(
2629 'Cannot hydrate Suspense in legacy mode. Switch from ' +
2630 'ReactDOM.hydrate(element, container) to ' +
2631 - 'ReactDOM.hydrateRoot(container, <App />)' +
2631 + 'ReactDOMClient.hydrateRoot(container, <App />)' +
2632 '.render(element) or remove the Suspense components from ' +
2633 'the server rendered components.',
2634 );
packages/react-reconciler/src/ReactFiberDevToolsHook.new.js
+5 -1
@@ -11,7 +11,11 @@ import type {Lane, Lanes} from './ReactFiberLane.new';
11 import type {Fiber, FiberRoot} from './ReactInternalTypes';
12 import type {ReactNodeList, Wakeable} from 'shared/ReactTypes';
13 import type {EventPriority} from './ReactEventPriorities.new';
14 -import type {DevToolsProfilingHooks} from 'react-devtools-shared/src/backend/types';
14 +// import type {DevToolsProfilingHooks} from 'react-devtools-shared/src/backend/types';
15 +// TODO: This import doesn't work because the DevTools depend on the DOM version of React
16 +// and to properly type check against DOM React we can't also type check again non-DOM
17 +// React which this hook might be in.
18 +type DevToolsProfilingHooks = any;
19
20 import {
21 getLabelForLane,
packages/react-reconciler/src/ReactFiberDevToolsHook.old.js
+5 -1
@@ -11,7 +11,11 @@ import type {Lane, Lanes} from './ReactFiberLane.old';
11 import type {Fiber, FiberRoot} from './ReactInternalTypes';
12 import type {ReactNodeList, Wakeable} from 'shared/ReactTypes';
13 import type {EventPriority} from './ReactEventPriorities.old';
14 -import type {DevToolsProfilingHooks} from 'react-devtools-shared/src/backend/types';
14 +// import type {DevToolsProfilingHooks} from 'react-devtools-shared/src/backend/types';
15 +// TODO: This import doesn't work because the DevTools depend on the DOM version of React
16 +// and to properly type check against DOM React we can't also type check again non-DOM
17 +// React which this hook might be in.
18 +type DevToolsProfilingHooks = any;
19
20 import {
21 getLabelForLane,
packages/react-reconciler/src/__tests__/ReactScope-test.internal.js
+3 -1
@@ -25,10 +25,12 @@ describe('ReactScope', () => {
25
26 describe('ReactDOM', () => {
27 let ReactDOM;
28 + let ReactDOMClient;
29 let container;
30
31 beforeEach(() => {
32 ReactDOM = require('react-dom');
33 + ReactDOMClient = require('react-dom/client');
34 ReactDOMServer = require('react-dom/server');
35 container = document.createElement('div');
36 document.body.appendChild(container);
@@ -312,7 +314,7 @@ describe('ReactScope', () => {
314 // On the client we don't have all data yet but we want to start
315 // hydrating anyway.
316 suspend = true;
315 - ReactDOM.hydrateRoot(container2, <App />);
317 + ReactDOMClient.hydrateRoot(container2, <App />);
318 Scheduler.unstable_flushAll();
319 jest.runAllTimers();
320
packages/react-reconciler/src/__tests__/ReactSuspenseEffectsSemanticsDOM-test.js
+3 -3
@@ -10,7 +10,7 @@
10 'use strict';
11
12 let React;
13 -let ReactDOM;
13 +let ReactDOMClient;
14 let act;
15
16 describe('ReactSuspenseEffectsSemanticsDOM', () => {
@@ -18,7 +18,7 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
18 jest.resetModules();
19
20 React = require('react');
21 - ReactDOM = require('react-dom');
21 + ReactDOMClient = require('react-dom/client');
22 act = require('jest-react').act;
23 });
24
@@ -63,7 +63,7 @@ describe('ReactSuspenseEffectsSemanticsDOM', () => {
63 }
64
65 act(() => {
66 - const root = ReactDOM.createRoot(document.createElement('div'));
66 + const root = ReactDOMClient.createRoot(document.createElement('div'));
67 root.render(<App />);
68 });
69
packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js
+5 -3
@@ -12,6 +12,7 @@
12 let React;
13 let ReactFeatureFlags;
14 let ReactDOM;
15 +let ReactDOMClient;
16 let Scheduler;
17 let mockDevToolsHook;
18 let allSchedulerTags;
@@ -90,6 +91,7 @@ describe('updaters', () => {
91
92 React = require('react');
93 ReactDOM = require('react-dom');
94 + ReactDOMClient = require('react-dom/client');
95 Scheduler = require('scheduler');
96
97 act = require('jest-react').act;
@@ -209,7 +211,7 @@ describe('updaters', () => {
211 return count;
212 };
213
212 - const root = ReactDOM.createRoot(document.createElement('div'));
214 + const root = ReactDOMClient.createRoot(document.createElement('div'));
215 await act(async () => {
216 root.render(<Parent />);
217 expect(Scheduler).toFlushAndYieldThrough([
@@ -354,7 +356,7 @@ describe('updaters', () => {
356 throw new Error('Hello');
357 };
358
357 - const root = ReactDOM.createRoot(document.createElement('div'));
359 + const root = ReactDOMClient.createRoot(document.createElement('div'));
360 await act(async () => {
361 root.render(<Parent shouldError={false} />);
362 });
@@ -404,7 +406,7 @@ describe('updaters', () => {
406 return null;
407 };
408
407 - const root = ReactDOM.createRoot(document.createElement('div'));
409 + const root = ReactDOMClient.createRoot(document.createElement('div'));
410 root.render(
411 <React.Fragment>
412 <SyncPriorityUpdater />
packages/react-reconciler/src/__tests__/useMutableSourceHydration-test.js
+8 -8
@@ -10,7 +10,7 @@
10 'use strict';
11
12 let React;
13 -let ReactDOM;
13 +let ReactDOMClient;
14 let ReactDOMServer;
15 let Scheduler;
16 let act;
@@ -22,7 +22,7 @@ describe('useMutableSourceHydration', () => {
22 jest.resetModules();
23
24 React = require('react');
25 - ReactDOM = require('react-dom');
25 + ReactDOMClient = require('react-dom/client');
26 ReactDOMServer = require('react-dom/server');
27 Scheduler = require('scheduler');
28
@@ -160,7 +160,7 @@ describe('useMutableSourceHydration', () => {
160 expect(source.listenerCount).toBe(0);
161
162 act(() => {
163 - ReactDOM.hydrateRoot(container, <TestComponent />, {
163 + ReactDOMClient.hydrateRoot(container, <TestComponent />, {
164 mutableSources: [mutableSource],
165 });
166 });
@@ -195,7 +195,7 @@ describe('useMutableSourceHydration', () => {
195
196 expect(() => {
197 act(() => {
198 - ReactDOM.hydrateRoot(container, <TestComponent />, {
198 + ReactDOMClient.hydrateRoot(container, <TestComponent />, {
199 mutableSources: [mutableSource],
200 onRecoverableError(error) {
201 Scheduler.unstable_yieldValue('Log error: ' + error.message);
@@ -256,7 +256,7 @@ describe('useMutableSourceHydration', () => {
256 act(() => {
257 if (gate(flags => flags.enableSyncDefaultUpdates)) {
258 React.startTransition(() => {
259 - ReactDOM.hydrateRoot(container, <TestComponent />, {
259 + ReactDOMClient.hydrateRoot(container, <TestComponent />, {
260 mutableSources: [mutableSource],
261 onRecoverableError(error) {
262 Scheduler.unstable_yieldValue('Log error: ' + error.message);
@@ -264,7 +264,7 @@ describe('useMutableSourceHydration', () => {
264 });
265 });
266 } else {
267 - ReactDOM.hydrateRoot(container, <TestComponent />, {
267 + ReactDOMClient.hydrateRoot(container, <TestComponent />, {
268 mutableSources: [mutableSource],
269 onRecoverableError(error) {
270 Scheduler.unstable_yieldValue('Log error: ' + error.message);
@@ -349,7 +349,7 @@ describe('useMutableSourceHydration', () => {
349 );
350 if (gate(flags => flags.enableSyncDefaultUpdates)) {
351 React.startTransition(() => {
352 - ReactDOM.hydrateRoot(container, fragment, {
352 + ReactDOMClient.hydrateRoot(container, fragment, {
353 mutableSources: [mutableSource],
354 onRecoverableError(error) {
355 Scheduler.unstable_yieldValue('Log error: ' + error.message);
@@ -357,7 +357,7 @@ describe('useMutableSourceHydration', () => {
357 });
358 });
359 } else {
360 - ReactDOM.hydrateRoot(container, fragment, {
360 + ReactDOMClient.hydrateRoot(container, fragment, {
361 mutableSources: [mutableSource],
362 onRecoverableError(error) {
363 Scheduler.unstable_yieldValue('Log error: ' + error.message);
packages/react-refresh/src/__tests__/ReactFresh-test.js
+3 -1
@@ -13,6 +13,7 @@
13
14 let React;
15 let ReactDOM;
16 +let ReactDOMClient;
17 let ReactFreshRuntime;
18 let Scheduler;
19 let act;
@@ -28,6 +29,7 @@ describe('ReactFresh', () => {
29 ReactFreshRuntime = require('react-refresh/runtime');
30 ReactFreshRuntime.injectIntoGlobalHook(global);
31 ReactDOM = require('react-dom');
32 + ReactDOMClient = require('react-dom/client');
33 Scheduler = require('scheduler');
34 act = require('jest-react').act;
35 createReactClass = require('create-react-class/factory')(
@@ -2437,7 +2439,7 @@ describe('ReactFresh', () => {
2439 };
2440 });
2441
2440 - const root = ReactDOM.createRoot(container);
2442 + const root = ReactDOMClient.createRoot(container);
2443 root.render(<AppV1 offscreen={true} />);
2444 expect(Scheduler).toFlushAndYieldThrough(['App#layout']);
2445 const el = container.firstChild;
packages/react-server-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js
+3 -3
@@ -9,7 +9,7 @@
9
10 let act;
11 let React;
12 -let ReactDOM;
12 +let ReactDOMClient;
13 let JSResourceReference;
14 let ReactDOMFlightRelayServer;
15 let ReactDOMFlightRelayClient;
@@ -21,7 +21,7 @@ describe('ReactFlightDOMRelay', () => {
21
22 act = require('jest-react').act;
23 React = require('react');
24 - ReactDOM = require('react-dom');
24 + ReactDOMClient = require('react-dom/client');
25 ReactDOMFlightRelayServer = require('react-server-dom-relay/server');
26 ReactDOMFlightRelayClient = require('react-server-dom-relay');
27 JSResourceReference = require('JSResourceReference');
@@ -100,7 +100,7 @@ describe('ReactFlightDOMRelay', () => {
100 const modelClient = readThrough(transport);
101
102 const container = document.createElement('div');
103 - const root = ReactDOM.createRoot(container);
103 + const root = ReactDOMClient.createRoot(container);
104 act(() => {
105 root.render(modelClient.greeting);
106 });
packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js
+7 -7
@@ -27,7 +27,7 @@ global.__webpack_require__ = function(id) {
27 let act;
28 let Stream;
29 let React;
30 -let ReactDOM;
30 +let ReactDOMClient;
31 let ReactServerDOMWriter;
32 let ReactServerDOMReader;
33
@@ -39,7 +39,7 @@ describe('ReactFlightDOM', () => {
39 act = require('jest-react').act;
40 Stream = require('stream');
41 React = require('react');
42 - ReactDOM = require('react-dom');
42 + ReactDOMClient = require('react-dom/client');
43 ReactServerDOMWriter = require('react-server-dom-webpack/writer.node.server');
44 ReactServerDOMReader = require('react-server-dom-webpack');
45 });
@@ -174,7 +174,7 @@ describe('ReactFlightDOM', () => {
174 const response = ReactServerDOMReader.createFromReadableStream(readable);
175
176 const container = document.createElement('div');
177 - const root = ReactDOM.createRoot(container);
177 + const root = ReactDOMClient.createRoot(container);
178 await act(async () => {
179 root.render(<App response={response} />);
180 });
@@ -212,7 +212,7 @@ describe('ReactFlightDOM', () => {
212 const response = ReactServerDOMReader.createFromReadableStream(readable);
213
214 const container = document.createElement('div');
215 - const root = ReactDOM.createRoot(container);
215 + const root = ReactDOMClient.createRoot(container);
216 await act(async () => {
217 root.render(<App response={response} />);
218 });
@@ -248,7 +248,7 @@ describe('ReactFlightDOM', () => {
248 const response = ReactServerDOMReader.createFromReadableStream(readable);
249
250 const container = document.createElement('div');
251 - const root = ReactDOM.createRoot(container);
251 + const root = ReactDOMClient.createRoot(container);
252 await act(async () => {
253 root.render(<App response={response} />);
254 });
@@ -388,7 +388,7 @@ describe('ReactFlightDOM', () => {
388 const response = ReactServerDOMReader.createFromReadableStream(readable);
389
390 const container = document.createElement('div');
391 - const root = ReactDOM.createRoot(container);
391 + const root = ReactDOMClient.createRoot(container);
392 await act(async () => {
393 root.render(
394 <Suspense fallback={<p>(loading)</p>}>
@@ -487,7 +487,7 @@ describe('ReactFlightDOM', () => {
487 }
488
489 const container = document.createElement('div');
490 - const root = ReactDOM.createRoot(container);
490 + const root = ReactDOMClient.createRoot(container);
491
492 const stream1 = getTestStream();
493 const {pipe} = ReactServerDOMWriter.renderToPipeableStream(
packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js
+3 -3
@@ -23,7 +23,7 @@ global.__webpack_require__ = function(id) {
23
24 let act;
25 let React;
26 -let ReactDOM;
26 +let ReactDOMClient;
27 let ReactServerDOMWriter;
28 let ReactServerDOMReader;
29
@@ -34,7 +34,7 @@ describe('ReactFlightDOMBrowser', () => {
34 webpackMap = {};
35 act = require('jest-react').act;
36 React = require('react');
37 - ReactDOM = require('react-dom');
37 + ReactDOMClient = require('react-dom/client');
38 ReactServerDOMWriter = require('react-server-dom-webpack/writer.browser.server');
39 ReactServerDOMReader = require('react-server-dom-webpack');
40 });
@@ -270,7 +270,7 @@ describe('ReactFlightDOMBrowser', () => {
270 const response = ReactServerDOMReader.createFromReadableStream(stream);
271
272 const container = document.createElement('div');
273 - const root = ReactDOM.createRoot(container);
273 + const root = ReactDOMClient.createRoot(container);
274 await act(async () => {
275 root.render(
276 <Suspense fallback={<p>(loading)</p>}>
packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee
+3 -1
@@ -8,6 +8,7 @@ LICENSE file in the root directory of this source tree.
8 PropTypes = null
9 React = null
10 ReactDOM = null
11 +ReactDOMClient = null
12 act = null
13
14 describe 'ReactCoffeeScriptClass', ->
@@ -20,10 +21,11 @@ describe 'ReactCoffeeScriptClass', ->
21 beforeEach ->
22 React = require 'react'
23 ReactDOM = require 'react-dom'
24 + ReactDOMClient = require 'react-dom/client'
25 act = require('jest-react').act
26 PropTypes = require 'prop-types'
27 container = document.createElement 'div'
26 - root = ReactDOM.createRoot container
28 + root = ReactDOMClient.createRoot container
29 attachedListener = null
30 renderedName = null
31 InnerComponent = class extends React.Component
packages/react/src/__tests__/ReactES6Class-test.js
+3 -1
@@ -12,6 +12,7 @@
12 let PropTypes;
13 let React;
14 let ReactDOM;
15 +let ReactDOMClient;
16 let act;
17
18 describe('ReactES6Class', () => {
@@ -29,9 +30,10 @@ describe('ReactES6Class', () => {
30 PropTypes = require('prop-types');
31 React = require('react');
32 ReactDOM = require('react-dom');
33 + ReactDOMClient = require('react-dom/client');
34 act = require('jest-react').act;
35 container = document.createElement('div');
34 - root = ReactDOM.createRoot(container);
36 + root = ReactDOMClient.createRoot(container);
37 attachedListener = null;
38 renderedName = null;
39 Inner = class extends React.Component {
packages/react/src/__tests__/ReactStrictMode-test.internal.js
+6 -6
@@ -11,13 +11,13 @@
11
12 describe('ReactStrictMode', () => {
13 let React;
14 - let ReactDOM;
14 + let ReactDOMClient;
15 let act;
16
17 beforeEach(() => {
18 jest.resetModules();
19 React = require('react');
20 - ReactDOM = require('react-dom');
20 + ReactDOMClient = require('react-dom/client');
21
22 act = require('jest-react').act;
23
@@ -51,7 +51,7 @@ describe('ReactStrictMode', () => {
51 it('should default to not strict', () => {
52 act(() => {
53 const container = document.createElement('div');
54 - const root = ReactDOM.createRoot(container);
54 + const root = ReactDOMClient.createRoot(container);
55 root.render(<Component label="A" />);
56 });
57
@@ -66,7 +66,7 @@ describe('ReactStrictMode', () => {
66 it('should support enabling strict mode via createRoot option', () => {
67 act(() => {
68 const container = document.createElement('div');
69 - const root = ReactDOM.createRoot(container, {
69 + const root = ReactDOMClient.createRoot(container, {
70 unstable_strictMode: true,
71 });
72 root.render(<Component label="A" />);
@@ -87,7 +87,7 @@ describe('ReactStrictMode', () => {
87 it('should include legacy + strict effects mode', () => {
88 act(() => {
89 const container = document.createElement('div');
90 - const root = ReactDOM.createRoot(container);
90 + const root = ReactDOMClient.createRoot(container);
91 root.render(
92 <React.StrictMode>
93 <Component label="A" />
@@ -110,7 +110,7 @@ describe('ReactStrictMode', () => {
110 it('should allow level to be increased with nesting', () => {
111 act(() => {
112 const container = document.createElement('div');
113 - const root = ReactDOM.createRoot(container);
113 + const root = ReactDOMClient.createRoot(container);
114 root.render(
115 <>
116 <Component label="A" />
packages/react/src/__tests__/ReactStrictMode-test.js
+10 -3
@@ -11,6 +11,7 @@
11
12 let React;
13 let ReactDOM;
14 +let ReactDOMClient;
15 let ReactDOMServer;
16 let Scheduler;
17 let PropTypes;
@@ -22,6 +23,7 @@ describe('ReactStrictMode', () => {
23 jest.resetModules();
24 React = require('react');
25 ReactDOM = require('react-dom');
26 + ReactDOMClient = require('react-dom/client');
27 ReactDOMServer = require('react-dom/server');
28 });
29
@@ -361,6 +363,7 @@ describe('Concurrent Mode', () => {
363
364 React = require('react');
365 ReactDOM = require('react-dom');
366 + ReactDOMClient = require('react-dom/client');
367 Scheduler = require('scheduler');
368 });
369
@@ -406,7 +409,7 @@ describe('Concurrent Mode', () => {
409 }
410
411 const container = document.createElement('div');
409 - const root = ReactDOM.createRoot(container);
412 + const root = ReactDOMClient.createRoot(container);
413 root.render(<StrictRoot />);
414 expect(() => Scheduler.unstable_flushAll()).toErrorDev(
415 [
@@ -468,7 +471,7 @@ Please update the following components: App`,
471 }
472
473 const container = document.createElement('div');
471 - const root = ReactDOM.createRoot(container);
474 + const root = ReactDOMClient.createRoot(container);
475 root.render(<StrictRoot />);
476
477 expect(() => {
@@ -544,7 +547,7 @@ Please update the following components: Parent`,
547 }
548
549 const container = document.createElement('div');
547 - const root = ReactDOM.createRoot(container);
550 + const root = ReactDOMClient.createRoot(container);
551 root.render(<StrictRoot foo={true} />);
552 expect(() =>
553 Scheduler.unstable_flushAll(),
@@ -623,6 +626,7 @@ describe('symbol checks', () => {
626 jest.resetModules();
627 React = require('react');
628 ReactDOM = require('react-dom');
629 + ReactDOMClient = require('react-dom/client');
630 });
631
632 it('should switch from StrictMode to a Fragment and reset state', () => {
@@ -735,6 +739,7 @@ describe('string refs', () => {
739 jest.resetModules();
740 React = require('react');
741 ReactDOM = require('react-dom');
742 + ReactDOMClient = require('react-dom/client');
743 });
744
745 it('should warn within a strict tree', () => {
@@ -820,6 +825,7 @@ describe('context legacy', () => {
825 jest.resetModules();
826 React = require('react');
827 ReactDOM = require('react-dom');
828 + ReactDOMClient = require('react-dom/client');
829 PropTypes = require('prop-types');
830 });
831
@@ -900,6 +906,7 @@ describe('context legacy', () => {
906 jest.resetModules();
907 React = require('react');
908 ReactDOM = require('react-dom');
909 + ReactDOMClient = require('react-dom/client');
910 });
911
912 if (ReactFeatureFlags.consoleManagedByDevToolsDuringStrictMode) {
packages/react/src/__tests__/ReactTypeScriptClass-test.ts
+3 -1
@@ -1,6 +1,7 @@
1 /// <reference path="./testDefinitions/PropTypes.d.ts" />
2 /// <reference path="./testDefinitions/React.d.ts" />
3 /// <reference path="./testDefinitions/ReactDOM.d.ts" />
4 +/// <reference path="./testDefinitions/ReactDOMClient.d.ts" />
5 /// <reference path="./testDefinitions/ReactInternalAct.d.ts" />
6
7 /*!
@@ -12,6 +13,7 @@
13
14 import React = require('react');
15 import ReactDOM = require('react-dom');
16 +import ReactDOMClient = require('react-dom/client');
17 import ReactDOMTestUtils = require('react-dom/test-utils');
18 import PropTypes = require('prop-types');
19 import internalAct = require('jest-react');
@@ -317,7 +319,7 @@ class ClassicRefs extends React.Component {
319 describe('ReactTypeScriptClass', function() {
320 beforeEach(function() {
321 container = document.createElement('div');
320 - root = ReactDOM.createRoot(container);
322 + root = ReactDOMClient.createRoot(container);
323 attachedListener = null;
324 renderedName = null;
325 });
packages/react/src/__tests__/testDefinitions/ReactDOM.d.ts
-1
@@ -13,7 +13,6 @@
13 */
14
15 declare module 'react-dom' {
16 - export function createRoot(container : any) : any
16 export function render(element : any, container : any) : any
17 export function unmountComponentAtNode(container : any) : void
18 export function findDOMNode(instance : any) : any
packages/react/src/__tests__/testDefinitions/ReactDOMClient.d.ts new
+18
@@ -0,0 +1,18 @@
1 +/*!
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +/**
9 + * TypeScript Definition File for React.
10 + *
11 + * Full type definitions are not yet officially supported. These are mostly
12 + * just helpers for the unit test.
13 + */
14 +
15 +declare module 'react-dom/client' {
16 + export function createRoot(container : any, options?: any) : any
17 + export function hydrateRoot(container : any, children: any, options?: any) : any
18 +}
packages/use-sync-external-store/src/__tests__/useSyncExternalStoreShared-test.js
+4 -2
@@ -13,6 +13,7 @@ let useSyncExternalStore;
13 let useSyncExternalStoreWithSelector;
14 let React;
15 let ReactDOM;
16 +let ReactDOMClient;
17 let Scheduler;
18 let act;
19 let useState;
@@ -46,6 +47,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
47
48 React = require('react');
49 ReactDOM = require('react-dom');
50 + ReactDOMClient = require('react-dom/client');
51 Scheduler = require('scheduler');
52 useState = React.useState;
53 useEffect = React.useEffect;
@@ -90,7 +92,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
92 // the correct behavior, despite the fact that the legacy root API
93 // triggers a warning in 18), write a test that uses
94 // createLegacyRoot directly.
93 - return ReactDOM.createRoot(container);
95 + return ReactDOMClient.createRoot(container);
96 } else {
97 ReactDOM.render(null, container);
98 return {
@@ -745,7 +747,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
747
748 if (gate(flags => !flags.enableUseSyncExternalStoreShim)) {
749 act(() => {
748 - ReactDOM.hydrateRoot(container, <App />);
750 + ReactDOMClient.hydrateRoot(container, <App />);
751 });
752 expect(Scheduler).toHaveYielded([
753 // First it hydrates the server rendered HTML
scripts/jest/typescript/preprocessor.js
+1 -1
@@ -42,7 +42,7 @@ function compile(content, contentFilename) {
42 let source;
43 const libRegex = /lib\.(.+\.)?d\.ts$/;
44 const jestRegex = /jest\.d\.ts/;
45 - const reactRegex = /(?:React|ReactDOM|ReactInternalAct|PropTypes)(?:\.d)?\.ts$/;
45 + const reactRegex = /(?:React|ReactDOM|ReactDOMClient|ReactInternalAct|PropTypes)(?:\.d)?\.ts$/;
46
47 // `path.normalize` is used to turn forward slashes in
48 // the file path into backslashes on Windows.
scripts/shared/inlinedHostConfigs.js
+10
@@ -18,12 +18,17 @@ module.exports = [
18 ],
19 paths: [
20 'react-dom',
21 + 'react-dom/client',
22 'react-dom/src/server/ReactDOMFizzServerNode.js', // react-dom/server.node
23 'react-server-dom-webpack',
24 'react-server-dom-webpack/writer',
25 'react-server-dom-webpack/writer.node.server',
26 'react-server-dom-webpack/src/ReactFlightDOMServerNode.js', // react-server-dom-webpack/writer.node.server
27 'react-client/src/ReactFlightClientStream.js', // We can only type check this in streaming configurations.
28 + 'react-devtools',
29 + 'react-devtools-core',
30 + 'react-devtools-shell',
31 + 'react-devtools-shared',
32 'react-interactions',
33 ],
34 isFlowTyped: true,
@@ -40,12 +45,17 @@ module.exports = [
45 ],
46 paths: [
47 'react-dom',
48 + 'react-dom/client',
49 'react-dom/unstable_testing',
50 'react-dom/src/server/ReactDOMFizzServerBrowser.js', // react-dom/server.browser
51 'react-server-dom-webpack',
52 'react-server-dom-webpack/writer.browser.server',
53 'react-server-dom-webpack/src/ReactFlightDOMServerBrowser.js', // react-server-dom-webpack/writer.browser.server
54 'react-client/src/ReactFlightClientStream.js', // We can only type check this in streaming configurations.
55 + 'react-devtools',
56 + 'react-devtools-core',
57 + 'react-devtools-shell',
58 + 'react-devtools-shared',
59 ],
60 isFlowTyped: true,
61 isServerSupported: true,