Skip to content

Commit 025127e

Browse files
committed
feat(react-dom): add 'no-render' rule
1 parent 121aa50 commit 025127e

File tree

9 files changed

+41
-24
lines changed

9 files changed

+41
-24
lines changed

apps/website/content/docs/rules/meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"dom-no-missing-button-type",
6363
"dom-no-missing-iframe-sandbox",
6464
"dom-no-namespace",
65+
"dom-no-render",
6566
"dom-no-render-return-value",
6667
"dom-no-script-url",
6768
"dom-no-unknown-property",

apps/website/content/docs/rules/overview.md

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -73,21 +73,22 @@ full: true
7373

7474
## DOM Rules
7575

76-
| Rule || Features | Description |
77-
| :----------------------------------------------------------------------------------------------- | :- | :------------ | :------------------------------------------------------------------------------------- |
78-
| [`no-dangerously-set-innerhtml`](./dom-no-dangerously-set-innerhtml) | 1️⃣ | `🔍` | Prevents DOM elements using `dangerouslySetInnerHTML`. |
79-
| [`no-dangerously-set-innerhtml-with-children`](./dom-no-dangerously-set-innerhtml-with-children) | 2️⃣ | `🔍` | Prevents DOM elements using `dangerouslySetInnerHTML` and `children` at the same time. |
80-
| [`no-find-dom-node`](./dom-no-find-dom-node) | 2️⃣ | `🔍` | Prevents using `findDOMNode`. |
81-
| [`no-flush-sync`](./dom-no-flush-sync) | 2️⃣ | `🔍` | Prevents using `flushSync`. |
82-
| [`no-missing-button-type`](./dom-no-missing-button-type) | 1️⃣ | `🔍` | Enforces explicit `type` attribute for `button` elements. |
83-
| [`no-missing-iframe-sandbox`](./dom-no-missing-iframe-sandbox) | 1️⃣ | `🔍` | Enforces explicit `sandbox` attribute for `iframe` elements. |
84-
| [`no-namespace`](./dom-no-namespace) | 2️⃣ | `🔍` | Enforces the absence of a `namespace` in React elements. |
85-
| [`no-render-return-value`](./dom-no-render-return-value) | 2️⃣ | `🔍` | Prevents using the return value of `ReactDOM.render`. |
86-
| [`no-script-url`](./dom-no-script-url) | 1️⃣ | `🔍` | Prevents using `javascript:` URLs as the value of attributes. |
87-
| [`no-unknown-property`](./dom-no-unknown-property) | 1️⃣ | `🔍` `🔧` `⚙️` | Prevents using unknown `DOM` property |
88-
| [`no-unsafe-iframe-sandbox`](./dom-no-unsafe-iframe-sandbox) | 1️⃣ | `🔍` | Enforces `sandbox` attribute for `iframe` elements is not set to unsafe combinations. |
89-
| [`no-unsafe-target-blank`](./dom-no-unsafe-target-blank) | 1️⃣ | `🔍` | Prevents using `target="_blank"` without `rel="noreferrer noopener"`. |
90-
| [`no-void-elements-with-children`](./dom-no-void-elements-with-children) | 2️⃣ | `🔍` | Prevents using `children` in void DOM elements. |
76+
| Rule || Features | Description | React DOM |
77+
| :----------------------------------------------------------------------------------------------- | :- | :------------ | :------------------------------------------------------------------------------------- | :-------: |
78+
| [`no-dangerously-set-innerhtml`](./dom-no-dangerously-set-innerhtml) | 1️⃣ | `🔍` | Prevents DOM elements using `dangerouslySetInnerHTML`. | |
79+
| [`no-dangerously-set-innerhtml-with-children`](./dom-no-dangerously-set-innerhtml-with-children) | 2️⃣ | `🔍` | Prevents DOM elements using `dangerouslySetInnerHTML` and `children` at the same time. | |
80+
| [`no-find-dom-node`](./dom-no-find-dom-node) | 2️⃣ | `🔍` | Prevents using `findDOMNode`. | |
81+
| [`no-flush-sync`](./dom-no-flush-sync) | 2️⃣ | `🔍` | Prevents using `flushSync`. | |
82+
| [`no-missing-button-type`](./dom-no-missing-button-type) | 1️⃣ | `🔍` | Enforces explicit `type` attribute for `button` elements. | |
83+
| [`no-missing-iframe-sandbox`](./dom-no-missing-iframe-sandbox) | 1️⃣ | `🔍` | Enforces explicit `sandbox` attribute for `iframe` elements. | |
84+
| [`no-namespace`](./dom-no-namespace) | 2️⃣ | `🔍` | Enforces the absence of a `namespace` in React elements. | |
85+
| [`no-render`](./dom-no-render) | 2️⃣ | `🔍` `🔄` | Replaces usages of `ReactDom.render()` with `createRoot(node).render()`. | >=18.0.0 |
86+
| [`no-render-return-value`](./dom-no-render-return-value) | 2️⃣ | `🔍` | Prevents using the return value of `ReactDOM.render`. | |
87+
| [`no-script-url`](./dom-no-script-url) | 1️⃣ | `🔍` | Prevents using `javascript:` URLs as the value of attributes. | |
88+
| [`no-unknown-property`](./dom-no-unknown-property) | 1️⃣ | `🔍` `🔧` `⚙️` | Prevents using unknown `DOM` property | |
89+
| [`no-unsafe-iframe-sandbox`](./dom-no-unsafe-iframe-sandbox) | 1️⃣ | `🔍` | Enforces `sandbox` attribute for `iframe` elements is not set to unsafe combinations. | |
90+
| [`no-unsafe-target-blank`](./dom-no-unsafe-target-blank) | 1️⃣ | `🔍` | Prevents using `target="_blank"` without `rel="noreferrer noopener"`. | |
91+
| [`no-void-elements-with-children`](./dom-no-void-elements-with-children) | 2️⃣ | `🔍` | Prevents using `children` in void DOM elements. | |
9192

9293
## Web API Rules
9394

packages/plugins/eslint-plugin-react-dom/src/configs/recommended.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const rules = {
1111
"react-dom/no-missing-button-type": "warn",
1212
"react-dom/no-missing-iframe-sandbox": "warn",
1313
"react-dom/no-namespace": "error",
14+
"react-dom/no-render": "error",
1415
"react-dom/no-render-return-value": "error",
1516
"react-dom/no-script-url": "warn",
1617
"react-dom/no-unknown-property": "warn",

packages/plugins/eslint-plugin-react-dom/src/plugin.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import noFlushSync from "./rules/no-flush-sync";
66
import noMissingButtonType from "./rules/no-missing-button-type";
77
import noMissingIframeSandbox from "./rules/no-missing-iframe-sandbox";
88
import noNamespace from "./rules/no-namespace";
9+
import noRender from "./rules/no-render";
910
import noRenderReturnValue from "./rules/no-render-return-value";
1011
import noScriptUrl from "./rules/no-script-url";
1112
import noUnknownProperty from "./rules/no-unknown-property";
@@ -26,6 +27,7 @@ export const plugin = {
2627
"no-missing-button-type": noMissingButtonType,
2728
"no-missing-iframe-sandbox": noMissingIframeSandbox,
2829
"no-namespace": noNamespace,
30+
"no-render": noRender,
2931
"no-render-return-value": noRenderReturnValue,
3032
"no-script-url": noScriptUrl,
3133
"no-unknown-property": noUnknownProperty,

packages/plugins/eslint-plugin-react-dom/src/rules/no-render-return-value.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,11 @@ ReactDOM.render(<div id="app" ref={doSomethingWithInst} />, document.body);
6464

6565
## Further Reading
6666

67-
- [Legacy React: react-dom/render](https://legacy.reactjs.org/docs/react-dom.html#render)
67+
- [React: react-dom/render](https://18.react.dev/reference/react-dom/render)
68+
69+
---
70+
71+
## See Also
72+
73+
- [no-render](./no-render.md)\
74+
Replaces usages of `ReactDom.render()` with `createRoot(node).render()`.

packages/plugins/eslint-plugin-react-dom/src/rules/no-render.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,9 @@ ReactDom.render(<Component />, document.getElementById("app"));
4646

4747
```tsx
4848
import { createRoot } from "react-dom/client";
49-
import ReactDom from "react-dom";
5049
import Component from "Component";
5150

52-
const root = createRoot(document.getElementById("app"));
53-
root.render(<Component />);
51+
createRoot(document.getElementById("app")).render(<Component />);
5452
```
5553

5654
## Implementation
@@ -60,6 +58,12 @@ root.render(<Component />);
6058

6159
## Further Reading
6260

61+
- [React: react-dom/render](https://18.react.dev/reference/react-dom/render)
62+
- [React: react-dom/createRoot](https://react.dev/reference/react-dom/client/createRoot)
63+
6364
---
6465

6566
## See Also
67+
68+
- [no-render-return-value](./no-render-return-value.md)\
69+
Prevents usage of the return value of `ReactDOM.render`.

packages/plugins/eslint-plugin-react-dom/src/rules/no-render.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,8 @@ export default createRule<[], MessageID>({
3535
create(context) {
3636
if (!context.sourceCode.text.includes("render")) return {};
3737
const settings = getSettingsFromContext(context);
38-
if (compare(settings.version, "19.0.0", "<")) {
39-
return {};
40-
}
38+
if (compare(settings.version, "18.0.0", "<")) return {};
39+
4140
const reactDomNames = new Set<string>();
4241
const renderNames = new Set<string>();
4342

@@ -54,9 +53,9 @@ export default createRule<[], MessageID>({
5453
return;
5554
case node.callee.type === T.MemberExpression
5655
&& node.callee.object.type === T.Identifier
57-
&& reactDomNames.has(node.callee.object.name)
5856
&& node.callee.property.type === T.Identifier
59-
&& node.callee.property.name === "render":
57+
&& node.callee.property.name === "render"
58+
&& reactDomNames.has(node.callee.object.name):
6059
context.report({
6160
messageId: "noRender",
6261
node,

packages/plugins/eslint-plugin/src/configs/all.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export const rules = {
6666
"@eslint-react/dom/no-missing-button-type": "warn",
6767
"@eslint-react/dom/no-missing-iframe-sandbox": "warn",
6868
"@eslint-react/dom/no-namespace": "error",
69+
"@eslint-react/dom/no-render": "error",
6970
"@eslint-react/dom/no-render-return-value": "error",
7071
"@eslint-react/dom/no-script-url": "warn",
7172
"@eslint-react/dom/no-unknown-property": "warn",

packages/plugins/eslint-plugin/src/configs/dom.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const rules = {
1212
"@eslint-react/dom/no-missing-button-type": "warn",
1313
"@eslint-react/dom/no-missing-iframe-sandbox": "warn",
1414
"@eslint-react/dom/no-namespace": "error",
15+
"@eslint-react/dom/no-render": "error",
1516
"@eslint-react/dom/no-render-return-value": "error",
1617
"@eslint-react/dom/no-script-url": "warn",
1718
"@eslint-react/dom/no-unknown-property": "warn",

0 commit comments

Comments
 (0)