Skip to content

Commit 838ac07

Browse files
sergei-startsevljharb
authored andcommitted
[New] no-deprecated: add React 18 deprecations
1 parent 45184ef commit 838ac07

File tree

4 files changed

+175
-3
lines changed

4 files changed

+175
-3
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
88
### Added
99
* [`display-name`]: add `checkContextObjects` option ([#3529][] @JulesBlm)
1010
* [`jsx-first-prop-new-line`]: add `multiprop` option ([#3533][] @haydncomley)
11+
* [`no-deprecated`]: add React 18 deprecations ([#3548][] @sergei-startsev)
1112

1213
### Fixed
1314
* [`no-array-index-key`]: consider flatMap ([#3530][] @k-yle)
1415
* [`jsx-curly-brace-presence`]: handle single and only expression template literals ([#3538][] @taozhou-glean)
1516
* [`no-unknown-property`]: allow `onLoad` on `source` (@ljharb)
1617

18+
[#3548]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3548
1719
[#3538]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3538
1820
[#3533]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3533
1921
[#3530]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3530

docs/rules/no-deprecated.md

+24-1
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,42 @@ import React, { PropTypes } from 'react';
3636
componentWillMount() { }
3737
componentWillReceiveProps() { }
3838
componentWillUpdate() { }
39+
40+
// React 18 deprecations
41+
import { render } from 'react-dom';
42+
ReactDOM.render(<div></div>, container);
43+
44+
import { hydrate } from 'react-dom';
45+
ReactDOM.hydrate(<div></div>, container);
46+
47+
import {unmountComponentAtNode} from 'react-dom';
48+
ReactDOM.unmountComponentAtNode(container);
49+
50+
import { renderToNodeStream } from 'react-dom/server';
51+
ReactDOMServer.renderToNodeStream(element);
3952
```
4053

4154
Examples of **correct** code for this rule:
4255

4356
```jsx
57+
// when React < 18
4458
ReactDOM.render(<MyComponent />, root);
4559

46-
// When [1, {"react": "0.13.0"}]
60+
// when React is < 0.14
4761
ReactDOM.findDOMNode(this.refs.foo);
4862

4963
import { PropTypes } from 'prop-types';
5064

5165
UNSAFE_componentWillMount() { }
5266
UNSAFE_componentWillReceiveProps() { }
5367
UNSAFE_componentWillUpdate() { }
68+
69+
ReactDOM.createPortal(child, container);
70+
71+
import { createRoot } from 'react-dom/client';
72+
const root = createRoot(container);
73+
root.unmount();
74+
75+
import { hydrateRoot } from 'react-dom/client';
76+
const root = hydrateRoot(container, <App/>);
5477
```

lib/rules/no-deprecated.js

+25
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ const report = require('../util/report');
2222
const MODULES = {
2323
react: ['React'],
2424
'react-addons-perf': ['ReactPerf', 'Perf'],
25+
'react-dom': ['ReactDOM'],
26+
'react-dom/server': ['ReactDOMServer'],
2527
};
2628

2729
// ------------------------------------------------------------------------------
@@ -82,6 +84,29 @@ function getDeprecated(pragma) {
8284
'https://reactjs.org/docs/react-component.html#unsafe_componentwillupdate. '
8385
+ 'Use https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles to automatically update your components.',
8486
];
87+
// 18.0.0
88+
// https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#deprecations
89+
deprecated['ReactDOM.render'] = [
90+
'18.0.0',
91+
'createRoot',
92+
'https://reactjs.org/link/switch-to-createroot',
93+
];
94+
deprecated['ReactDOM.hydrate'] = [
95+
'18.0.0',
96+
'hydrateRoot',
97+
'https://reactjs.org/link/switch-to-createroot',
98+
];
99+
deprecated['ReactDOM.unmountComponentAtNode'] = [
100+
'18.0.0',
101+
'root.unmount',
102+
'https://reactjs.org/link/switch-to-createroot',
103+
];
104+
deprecated['ReactDOMServer.renderToNodeStream'] = [
105+
'18.0.0',
106+
'renderToPipeableStream',
107+
'https://reactjs.org/docs/react-dom-server.html#rendertonodestream',
108+
];
109+
85110
return deprecated;
86111
}
87112

tests/lib/rules/no-deprecated.js

+124-2
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ ruleTester.run('no-deprecated', rule, {
4848
// Not deprecated
4949
'var element = React.createElement(\'p\', {}, null);',
5050
'var clone = React.cloneElement(element);',
51-
'ReactDOM.render(element, container);',
52-
'ReactDOM.unmountComponentAtNode(container);',
51+
'ReactDOM.cloneElement(child, container);',
5352
'ReactDOM.findDOMNode(instance);',
53+
'ReactDOM.createPortal(child, container);',
5454
'ReactDOMServer.renderToString(element);',
5555
'ReactDOMServer.renderToStaticMarkup(element);',
5656
{
@@ -119,6 +119,40 @@ ruleTester.run('no-deprecated', rule, {
119119
let { default: defaultReactExport, ...allReactExports } = React;
120120
`,
121121
},
122+
// React < 18
123+
{
124+
code: `
125+
import { render, hydrate } from 'react-dom';
126+
import { renderToNodeStream } from 'react-dom/server';
127+
ReactDOM.render(element, container);
128+
ReactDOM.unmountComponentAtNode(container);
129+
ReactDOMServer.renderToNodeStream(element);
130+
`,
131+
settings: { react: { version: '17.999.999' } },
132+
},
133+
// React 18 API
134+
{
135+
code: `
136+
import ReactDOM, { createRoot } from 'react-dom/client';
137+
ReactDOM.createRoot(container);
138+
const root = createRoot(container);
139+
root.unmount();
140+
`,
141+
},
142+
{
143+
code: `
144+
import ReactDOM, { hydrateRoot } from 'react-dom/client';
145+
ReactDOM.hydrateRoot(container, <App/>);
146+
hydrateRoot(container, <App/>);
147+
`,
148+
},
149+
{
150+
code: `
151+
import ReactDOMServer, { renderToPipeableStream } from 'react-dom/server';
152+
ReactDOMServer.renderToPipeableStream(<App />, {});
153+
renderToPipeableStream(<App />, {});
154+
`,
155+
},
122156
]),
123157

124158
invalid: parsers.all([
@@ -454,5 +488,93 @@ ruleTester.run('no-deprecated', rule, {
454488
),
455489
],
456490
},
491+
{
492+
code: `
493+
import { render } from 'react-dom';
494+
ReactDOM.render(<div></div>, container);
495+
`,
496+
errors: [
497+
errorMessage(
498+
'ReactDOM.render',
499+
'18.0.0',
500+
'createRoot',
501+
'https://reactjs.org/link/switch-to-createroot',
502+
{ type: 'ImportDeclaration', line: 2, column: 9 }
503+
),
504+
errorMessage(
505+
'ReactDOM.render',
506+
'18.0.0',
507+
'createRoot',
508+
'https://reactjs.org/link/switch-to-createroot',
509+
{ type: 'MemberExpression', line: 3, column: 9 }
510+
),
511+
],
512+
},
513+
{
514+
code: `
515+
import { hydrate } from 'react-dom';
516+
ReactDOM.hydrate(<div></div>, container);
517+
`,
518+
errors: [
519+
errorMessage(
520+
'ReactDOM.hydrate',
521+
'18.0.0',
522+
'hydrateRoot',
523+
'https://reactjs.org/link/switch-to-createroot',
524+
{ type: 'ImportDeclaration', line: 2, column: 9 }
525+
),
526+
errorMessage(
527+
'ReactDOM.hydrate',
528+
'18.0.0',
529+
'hydrateRoot',
530+
'https://reactjs.org/link/switch-to-createroot',
531+
{ type: 'MemberExpression', line: 3, column: 9 }
532+
),
533+
],
534+
},
535+
{
536+
code: `
537+
import { unmountComponentAtNode } from 'react-dom';
538+
ReactDOM.unmountComponentAtNode(container);
539+
`,
540+
errors: [
541+
errorMessage(
542+
'ReactDOM.unmountComponentAtNode',
543+
'18.0.0',
544+
'root.unmount',
545+
'https://reactjs.org/link/switch-to-createroot',
546+
{ type: 'ImportDeclaration', line: 2, column: 9 }
547+
),
548+
errorMessage(
549+
'ReactDOM.unmountComponentAtNode',
550+
'18.0.0',
551+
'root.unmount',
552+
'https://reactjs.org/link/switch-to-createroot',
553+
{ type: 'MemberExpression', line: 3, column: 9 }
554+
),
555+
],
556+
},
557+
{
558+
code: `
559+
import { renderToNodeStream } from 'react-dom/server';
560+
ReactDOMServer.renderToNodeStream(element);
561+
`,
562+
errors: [
563+
errorMessage(
564+
'ReactDOMServer.renderToNodeStream',
565+
'18.0.0',
566+
'renderToPipeableStream',
567+
'https://reactjs.org/docs/react-dom-server.html#rendertonodestream',
568+
{ type: 'ImportDeclaration', line: 2, column: 9 }
569+
),
570+
errorMessage(
571+
'ReactDOMServer.renderToNodeStream',
572+
'18.0.0',
573+
'renderToPipeableStream',
574+
'https://reactjs.org/docs/react-dom-server.html#rendertonodestream',
575+
{ type: 'MemberExpression', line: 3, column: 9 }
576+
),
577+
],
578+
},
457579
]),
458580
});

0 commit comments

Comments
 (0)