Skip to content

Commit 1780659

Browse files
sebmarkbageacdlite
andauthored
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 <[email protected]>
1 parent 75662d6 commit 1780659

File tree

72 files changed

+648
-356
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+648
-356
lines changed

fixtures/blocks/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import React from 'react';
9-
import {createRoot} from 'react-dom';
9+
import {createRoot} from 'react-dom/client';
1010
import './index.css';
1111
import Router from './Router';
1212

fixtures/concurrent/time-slicing/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, {PureComponent, unstable_startTransition} from 'react';
2-
import {createRoot} from 'react-dom';
2+
import {createRoot} from 'react-dom/client';
33
import _ from 'lodash';
44
import Charts from './Charts';
55
import Clock from './Clock';

fixtures/ssr/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import {hydrateRoot} from 'react-dom';
2+
import {hydrateRoot} from 'react-dom/client';
33

44
import App from './components/App';
55

fixtures/ssr/yarn.lock

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4265,7 +4265,7 @@ longest@^1.0.1:
42654265
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
42664266
integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
42674267

4268-
loose-envify@^1.0.0:
4268+
loose-envify@^1.0.0, loose-envify@^1.1.0:
42694269
version "1.4.0"
42704270
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
42714271
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -5945,6 +5945,14 @@ sax@^1.2.1, sax@~1.2.1:
59455945
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
59465946
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
59475947

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+
59485956
"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0:
59495957
version "5.7.1"
59505958
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"

fixtures/ssr2/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
*/
88

9-
import {hydrateRoot} from 'react-dom';
9+
import {hydrateRoot} from 'react-dom/client';
1010
import App from './App';
1111

1212
hydrateRoot(document, <App assets={window.assetManifest} />);

packages/react-devtools-core/src/standalone.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ import {createElement} from 'react';
1111
import {
1212
// $FlowFixMe Flow does not yet know about flushSync()
1313
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';
1716
import Bridge from 'react-devtools-shared/src/bridge';
1817
import Store from 'react-devtools-shared/src/devtools/store';
1918
import {

packages/react-devtools-core/webpack.standalone.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ module.exports = {
6464
react: resolve(builtModulesDir, 'react'),
6565
'react-debug-tools': resolve(builtModulesDir, 'react-debug-tools'),
6666
'react-devtools-feature-flags': resolveFeatureFlags(featureFlagTarget),
67+
'react-dom/client': resolve(builtModulesDir, 'react-dom/client'),
6768
'react-dom': resolve(builtModulesDir, 'react-dom'),
6869
'react-is': resolve(builtModulesDir, 'react-is'),
6970
scheduler: resolve(builtModulesDir, 'scheduler'),

packages/react-devtools-extensions/webpack.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ module.exports = {
7676
react: resolve(builtModulesDir, 'react'),
7777
'react-debug-tools': resolve(builtModulesDir, 'react-debug-tools'),
7878
'react-devtools-feature-flags': resolveFeatureFlags(featureFlagTarget),
79+
'react-dom/client': resolve(builtModulesDir, 'react-dom/client'),
7980
'react-dom': resolve(builtModulesDir, 'react-dom'),
8081
'react-is': resolve(builtModulesDir, 'react-is'),
8182
scheduler: resolve(builtModulesDir, 'scheduler'),

packages/react-devtools-inline/README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ const contentWindow = iframe.contentWindow;
6060
const DevTools = initialize(contentWindow);
6161
```
6262

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`.**
6464

6565
## Examples
6666

@@ -110,8 +110,7 @@ const DevTools = initializeFrontend(contentWindow);
110110
// as setting the src of the <iframe> would load a new page (without the injected backend).
111111

112112
// <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.
115114

116115
// Let the backend know the frontend is ready and listening.
117116
activateBackend(contentWindow);
@@ -154,8 +153,7 @@ const { contentWindow } = iframe;
154153

155154
// Initialize DevTools UI to listen to the iframe.
156155
// 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.
159157
const DevTools = initialize(contentWindow);
160158

161159
// Let the backend know to initialize itself.

packages/react-devtools-inline/webpack.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ module.exports = {
5151
externals: {
5252
react: 'react',
5353
'react-dom': 'react-dom',
54+
'react-dom/client': 'react-dom/client',
5455
'react-is': 'react-is',
5556
scheduler: 'scheduler',
5657
},

0 commit comments

Comments
 (0)