Skip to content

Commit f8c0827

Browse files
committed
Remove data-reactroot from server rendering and hydration heuristic
This was used to implicitly hydrate if you call ReactDOM.render. We've had a warning to explicitly use ReactDOM.hydrate(...) instead of ReactDOM.render(...). We can now remove this from the generated markup. (And avoid adding it to Fizz.) This is a little strange to do now since we're trying hard to make the root API work the same. But if we kept it, we'd need to keep it in the generated output which adds unnecessary bytes. It also risks people relying on it, in the Fizz world where as this is an opportunity to create that clean state. We could possibly only keep it in the old server rendering APIs but then that creates an implicit dependency between which server API and which client API that you use. Currently you can really mix and match either way.
1 parent 46491dc commit f8c0827

16 files changed

+31
-456
lines changed

packages/react-dom/src/__tests__/ReactCompositeComponent-test.js

-39
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ let ChildUpdates;
1313
let MorphingComponent;
1414
let React;
1515
let ReactDOM;
16-
let ReactDOMServer;
1716
let ReactCurrentOwner;
1817
let ReactTestUtils;
1918
let PropTypes;
@@ -65,7 +64,6 @@ describe('ReactCompositeComponent', () => {
6564
jest.resetModules();
6665
React = require('react');
6766
ReactDOM = require('react-dom');
68-
ReactDOMServer = require('react-dom/server');
6967
ReactCurrentOwner = require('react')
7068
.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner;
7169
ReactTestUtils = require('react-dom/test-utils');
@@ -170,43 +168,6 @@ describe('ReactCompositeComponent', () => {
170168
expect(el.tagName).toBe('A');
171169
});
172170

173-
it('should not thrash a server rendered layout with client side one', () => {
174-
class Child extends React.Component {
175-
render() {
176-
return null;
177-
}
178-
}
179-
180-
class Parent extends React.Component {
181-
render() {
182-
return (
183-
<div>
184-
<Child />
185-
</div>
186-
);
187-
}
188-
}
189-
190-
const markup = ReactDOMServer.renderToString(<Parent />);
191-
192-
// Old API based on heuristic
193-
let container = document.createElement('div');
194-
container.innerHTML = markup;
195-
expect(() =>
196-
ReactDOM.render(<Parent />, container),
197-
).toWarnDev(
198-
'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
199-
'will stop working in React v18. Replace the ReactDOM.render() call ' +
200-
'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
201-
{withoutStack: true},
202-
);
203-
204-
// New explicit API
205-
container = document.createElement('div');
206-
container.innerHTML = markup;
207-
ReactDOM.hydrate(<Parent />, container);
208-
});
209-
210171
it('should react to state changes from callbacks', () => {
211172
const container = document.createElement('div');
212173
document.body.appendChild(container);

packages/react-dom/src/__tests__/ReactLegacyContextDisabled-test.internal.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,7 @@ describe('ReactLegacyContextDisabled', () => {
139139
'LegacyFnConsumer uses the legacy contextTypes API which is no longer supported. ' +
140140
'Use React.createContext() with React.useContext() instead.',
141141
]);
142-
expect(text).toBe(
143-
'<span data-reactroot="">{}<!-- -->undefined<!-- -->undefined</span>',
144-
);
142+
expect(text).toBe('<span>{}<!-- -->undefined<!-- -->undefined</span>');
145143
expect(lifecycleContextLog).toEqual([{}, {}, {}]);
146144
});
147145

packages/react-dom/src/__tests__/ReactRenderDocument-test.js

-219
Original file line numberDiff line numberDiff line change
@@ -33,225 +33,6 @@ describe('rendering React components at document', () => {
3333
ReactDOMServer = require('react-dom/server');
3434
});
3535

36-
describe('with old implicit hydration API', () => {
37-
function expectDeprecationWarningWithFiber(callback) {
38-
expect(
39-
callback,
40-
).toWarnDev(
41-
'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
42-
'will stop working in React v18. Replace the ReactDOM.render() call ' +
43-
'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
44-
{withoutStack: true},
45-
);
46-
}
47-
48-
it('should be able to adopt server markup', () => {
49-
class Root extends React.Component {
50-
render() {
51-
return (
52-
<html>
53-
<head>
54-
<title>Hello World</title>
55-
</head>
56-
<body>{'Hello ' + this.props.hello}</body>
57-
</html>
58-
);
59-
}
60-
}
61-
62-
const markup = ReactDOMServer.renderToString(<Root hello="world" />);
63-
const testDocument = getTestDocument(markup);
64-
const body = testDocument.body;
65-
66-
expectDeprecationWarningWithFiber(() =>
67-
ReactDOM.render(<Root hello="world" />, testDocument),
68-
);
69-
expect(testDocument.body.innerHTML).toBe('Hello world');
70-
71-
ReactDOM.render(<Root hello="moon" />, testDocument);
72-
expect(testDocument.body.innerHTML).toBe('Hello moon');
73-
74-
expect(body === testDocument.body).toBe(true);
75-
});
76-
77-
it('should not be able to unmount component from document node', () => {
78-
class Root extends React.Component {
79-
render() {
80-
return (
81-
<html>
82-
<head>
83-
<title>Hello World</title>
84-
</head>
85-
<body>Hello world</body>
86-
</html>
87-
);
88-
}
89-
}
90-
91-
const markup = ReactDOMServer.renderToString(<Root />);
92-
const testDocument = getTestDocument(markup);
93-
expectDeprecationWarningWithFiber(() =>
94-
ReactDOM.render(<Root />, testDocument),
95-
);
96-
expect(testDocument.body.innerHTML).toBe('Hello world');
97-
98-
// In Fiber this actually works. It might not be a good idea though.
99-
ReactDOM.unmountComponentAtNode(testDocument);
100-
expect(testDocument.firstChild).toBe(null);
101-
});
102-
103-
it('should not be able to switch root constructors', () => {
104-
class Component extends React.Component {
105-
render() {
106-
return (
107-
<html>
108-
<head>
109-
<title>Hello World</title>
110-
</head>
111-
<body>Hello world</body>
112-
</html>
113-
);
114-
}
115-
}
116-
117-
class Component2 extends React.Component {
118-
render() {
119-
return (
120-
<html>
121-
<head>
122-
<title>Hello World</title>
123-
</head>
124-
<body>Goodbye world</body>
125-
</html>
126-
);
127-
}
128-
}
129-
130-
const markup = ReactDOMServer.renderToString(<Component />);
131-
const testDocument = getTestDocument(markup);
132-
133-
expectDeprecationWarningWithFiber(() =>
134-
ReactDOM.render(<Component />, testDocument),
135-
);
136-
expect(testDocument.body.innerHTML).toBe('Hello world');
137-
138-
// This works but is probably a bad idea.
139-
ReactDOM.render(<Component2 />, testDocument);
140-
141-
expect(testDocument.body.innerHTML).toBe('Goodbye world');
142-
});
143-
144-
it('should be able to mount into document', () => {
145-
class Component extends React.Component {
146-
render() {
147-
return (
148-
<html>
149-
<head>
150-
<title>Hello World</title>
151-
</head>
152-
<body>{this.props.text}</body>
153-
</html>
154-
);
155-
}
156-
}
157-
158-
const markup = ReactDOMServer.renderToString(
159-
<Component text="Hello world" />,
160-
);
161-
const testDocument = getTestDocument(markup);
162-
163-
expectDeprecationWarningWithFiber(() =>
164-
ReactDOM.render(<Component text="Hello world" />, testDocument),
165-
);
166-
167-
expect(testDocument.body.innerHTML).toBe('Hello world');
168-
});
169-
170-
it('renders over an existing text child without throwing', () => {
171-
const container = document.createElement('div');
172-
container.textContent = 'potato';
173-
ReactDOM.render(<div>parsnip</div>, container);
174-
expect(container.textContent).toBe('parsnip');
175-
// We don't expect a warning about new hydration API here because
176-
// we aren't sure if the user meant to hydrate or replace a stub node.
177-
// We would see a warning if the container had React-rendered HTML in it.
178-
});
179-
180-
it('should give helpful errors on state desync', () => {
181-
class Component extends React.Component {
182-
render() {
183-
return (
184-
<html>
185-
<head>
186-
<title>Hello World</title>
187-
</head>
188-
<body>{this.props.text}</body>
189-
</html>
190-
);
191-
}
192-
}
193-
194-
const markup = ReactDOMServer.renderToString(
195-
<Component text="Goodbye world" />,
196-
);
197-
const testDocument = getTestDocument(markup);
198-
199-
expect(() => {
200-
expect(() =>
201-
ReactDOM.render(<Component text="Hello world" />, testDocument),
202-
).toWarnDev(
203-
'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
204-
'will stop working in React v18. Replace the ReactDOM.render() call ' +
205-
'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
206-
{withoutStack: true},
207-
);
208-
}).toErrorDev('Warning: Text content did not match.');
209-
});
210-
211-
it('should throw on full document render w/ no markup', () => {
212-
const testDocument = getTestDocument();
213-
214-
class Component extends React.Component {
215-
render() {
216-
return (
217-
<html>
218-
<head>
219-
<title>Hello World</title>
220-
</head>
221-
<body>{this.props.text}</body>
222-
</html>
223-
);
224-
}
225-
}
226-
227-
ReactDOM.render(<Component text="Hello world" />, testDocument);
228-
expect(testDocument.body.innerHTML).toBe('Hello world');
229-
// We don't expect a warning about new hydration API here because
230-
// we aren't sure if the user meant to hydrate or replace the document.
231-
// We would see a warning if the document had React-rendered HTML in it.
232-
});
233-
234-
it('supports findDOMNode on full-page components', () => {
235-
const tree = (
236-
<html>
237-
<head>
238-
<title>Hello World</title>
239-
</head>
240-
<body>Hello world</body>
241-
</html>
242-
);
243-
244-
const markup = ReactDOMServer.renderToString(tree);
245-
const testDocument = getTestDocument(markup);
246-
let component;
247-
expectDeprecationWarningWithFiber(() => {
248-
component = ReactDOM.render(tree, testDocument);
249-
});
250-
expect(testDocument.body.innerHTML).toBe('Hello world');
251-
expect(ReactDOM.findDOMNode(component).tagName).toBe('HTML');
252-
});
253-
});
254-
25536
describe('with new explicit hydration API', () => {
25637
it('should be able to adopt server markup', () => {
25738
class Root extends React.Component {

packages/react-dom/src/__tests__/ReactServerRendering-test.js

+5-17
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,12 @@ describe('ReactDOMServer', () => {
3131
describe('renderToString', () => {
3232
it('should generate simple markup', () => {
3333
const response = ReactDOMServer.renderToString(<span>hello world</span>);
34-
expect(response).toMatch(
35-
new RegExp('<span data-reactroot=""' + '>hello world</span>'),
36-
);
34+
expect(response).toMatch(new RegExp('<span' + '>hello world</span>'));
3735
});
3836

3937
it('should generate simple markup for self-closing tags', () => {
4038
const response = ReactDOMServer.renderToString(<img />);
41-
expect(response).toMatch(new RegExp('<img data-reactroot=""' + '/>'));
39+
expect(response).toMatch(new RegExp('<img' + '/>'));
4240
});
4341

4442
it('should generate comment markup for component returns null', () => {
@@ -74,10 +72,7 @@ describe('ReactDOMServer', () => {
7472
const response = ReactDOMServer.renderToString(<Parent />);
7573
expect(response).toMatch(
7674
new RegExp(
77-
'<div ' +
78-
'data-reactroot' +
79-
'=""' +
80-
'>' +
75+
'<div>' +
8176
'<span' +
8277
'>' +
8378
'My name is <!-- -->child' +
@@ -136,12 +131,7 @@ describe('ReactDOMServer', () => {
136131

137132
expect(response).toMatch(
138133
new RegExp(
139-
'<span ' +
140-
'data-reactroot' +
141-
'=""' +
142-
'>' +
143-
'Component name: <!-- -->TestComponent' +
144-
'</span>',
134+
'<span>' + 'Component name: <!-- -->TestComponent' + '</span>',
145135
),
146136
);
147137
expect(lifecycle).toEqual([
@@ -580,9 +570,7 @@ describe('ReactDOMServer', () => {
580570
it('should generate simple markup', () => {
581571
const SuccessfulElement = React.createElement(() => <img />);
582572
const response = ReactDOMServer.renderToNodeStream(SuccessfulElement);
583-
expect(response.read().toString()).toMatch(
584-
new RegExp('<img data-reactroot=""' + '/>'),
585-
);
573+
expect(response.read().toString()).toMatch(new RegExp('<img' + '/>'));
586574
});
587575

588576
it('should handle errors correctly', () => {

0 commit comments

Comments
 (0)