Skip to content

Commit 509dc1a

Browse files
authored
feat: add rule react/no-unsafe-component-will-receive-props, closes #191 (#196)
1 parent bf39f66 commit 509dc1a

13 files changed

+484
-2
lines changed

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
## v0.9.2 (Draft)
2+
3+
### Release Notes
4+
5+
#### Add rule `react/no-component-will-update`
6+
7+
#### Add rule `react/no-unsafe-component-will-update`
8+
9+
#### Add rule `react/no-component-will-receive-props`
10+
11+
#### Add rule `react/no-unsafe-component-will-receive-props`
12+
13+
---
14+
15+
#### 🏠 Internal
16+
17+
- `@eslint-react/eslint-plugin-react`
18+
- Add rule `react/no-component-will-update`.
19+
- Add rule `react/no-unsafe-component-will-update`.
20+
- Add rule `react/no-component-will-receive-props`.
21+
- Add rule `react/no-unsafe-component-will-receive-props`.
22+
23+
#### Authors: 1
24+
25+
- Eva1ent ([@Rel1cx](https://github.com/Rel1cx))
26+
27+
---
28+
129
## v0.9.1 (Tue Dec 5 2023)
230

331
### Release Notes

packages/eslint-plugin-react/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import noChildrenToArray from "./rules/no-children-to-array";
1111
import noClassComponent from "./rules/no-class-component";
1212
import noCloneElement from "./rules/no-clone-element";
1313
import noComponentWillMount from "./rules/no-component-will-mount";
14+
import noComponentWillReceiveProps from "./rules/no-component-will-receive-props";
1415
import noComponentWillUpdate from "./rules/no-component-will-update";
1516
import noConstructedContextValue from "./rules/no-constructed-context-value";
1617
import noCreateRef from "./rules/no-create-ref";
@@ -26,6 +27,7 @@ import noRenderReturnValue from "./rules/no-render-return-value";
2627
import noScriptUrl from "./rules/no-script-url";
2728
import noStringRefs from "./rules/no-string-refs";
2829
import noUnsafeComponentWillMount from "./rules/no-unsafe-component-will-mount";
30+
import noUnsafeComponentWillReceiveProps from "./rules/no-unsafe-component-will-receive-props";
2931
import noUnsafeComponentWillUpdate from "./rules/no-unsafe-component-will-update";
3032
import noUnsafeIframeSandbox from "./rules/no-unsafe-iframe-sandbox";
3133
import noUnsafeTargetBlank from "./rules/no-unsafe-target-blank";
@@ -49,6 +51,7 @@ export const rules = {
4951
"no-class-component": noClassComponent,
5052
"no-clone-element": noCloneElement,
5153
"no-component-will-mount": noComponentWillMount,
54+
"no-component-will-receive-props": noComponentWillReceiveProps,
5255
"no-component-will-update": noComponentWillUpdate,
5356
"no-constructed-context-value": noConstructedContextValue,
5457
"no-create-ref": noCreateRef,
@@ -64,6 +67,7 @@ export const rules = {
6467
"no-script-url": noScriptUrl,
6568
"no-string-refs": noStringRefs,
6669
"no-unsafe-component-will-mount": noUnsafeComponentWillMount,
70+
"no-unsafe-component-will-receive-props": noUnsafeComponentWillReceiveProps,
6771
"no-unsafe-component-will-update": noUnsafeComponentWillUpdate,
6872
"no-unsafe-iframe-sandbox": noUnsafeIframeSandbox,
6973
"no-unsafe-target-blank": noUnsafeTargetBlank,

packages/eslint-plugin-react/src/rules/no-component-will-mount.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Prevents usage of `componentWillMount` in class components.
1010

1111
## Why is this bad?
1212

13-
This API has been renamed from componentWillMount to UNSAFE_componentWillMount. The old name has been deprecated. In a future major version of React, only the new name will work.
13+
This API has been renamed from `componentWillMount` to `UNSAFE_componentWillMount`. The old name has been deprecated. In a future major version of React, only the new name will work.
1414

1515
Run the [rename-unsafe-lifecycles codemod](https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles) to automatically update your components.
1616

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# react/no-component-will-receive-props
2+
3+
## Rule category
4+
5+
Correctness.
6+
7+
## What it does
8+
9+
Prevents usage of `componentWillReceiveProps` in class components.
10+
11+
## Why is this bad?
12+
13+
This API has been renamed from `componentWillReceiveProps` to `UNSAFE_componentWillReceiveProps`. The old name has been deprecated. In a future major version of React, only the new name will work.
14+
15+
Run the [rename-unsafe-lifecycles codemod](https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles) to automatically update your components.
16+
17+
## Examples
18+
19+
### ❌ Incorrect
20+
21+
```tsx
22+
import React from "react";
23+
24+
class MyComponent extends React.Component {
25+
componentWillReceiveProps() {
26+
// ...
27+
}
28+
}
29+
```
30+
31+
### ✅ Correct
32+
33+
```tsx
34+
import React from "react";
35+
36+
class MyComponent extends React.Component {
37+
UNSAFE_componentWillReceiveProps() {
38+
// ...
39+
}
40+
}
41+
```
42+
43+
## Further Reading
44+
45+
- [react.dev Legacy React APIs componentWillReceiveProps](https://react.dev/reference/react/Component#componentwillreceiveprops)
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import dedent from "dedent";
2+
3+
import { allValid, defaultParserOptions, RuleTester } from "../../../../test";
4+
import rule, { RULE_NAME } from "./no-component-will-update";
5+
6+
const ruleTester = new RuleTester({
7+
parser: "@typescript-eslint/parser",
8+
parserOptions: defaultParserOptions,
9+
});
10+
11+
ruleTester.run(RULE_NAME, rule, {
12+
valid: [
13+
...allValid,
14+
dedent`
15+
class Foo extends Bar {
16+
componentWillUpdate() {}
17+
}
18+
`,
19+
dedent`
20+
import React from "react";
21+
22+
class Foo extends React.Component {
23+
24+
UNSAFE_componentWillUpdate() {}
25+
26+
render() {
27+
return <div />;
28+
}
29+
}
30+
`,
31+
dedent`
32+
import React from "react";
33+
34+
class Foo extends React.PureComponent {
35+
36+
UNSAFE_componentWillUpdate() {}
37+
38+
render() {
39+
return <div />;
40+
}
41+
}
42+
`,
43+
],
44+
invalid: [
45+
{
46+
code: dedent`
47+
import React from "react";
48+
49+
class Foo extends React.Component {
50+
51+
componentWillUpdate() {}
52+
53+
render() {
54+
return <div />;
55+
}
56+
}
57+
`,
58+
errors: [
59+
{
60+
messageId: "NO_COMPONENT_WILL_UPDATE",
61+
},
62+
],
63+
},
64+
{
65+
code: dedent`
66+
import React from "react";
67+
68+
class Foo extends React.PureComponent {
69+
70+
componentWillUpdate() {}
71+
72+
render() {
73+
return <div />;
74+
}
75+
}
76+
`,
77+
errors: [
78+
{
79+
messageId: "NO_COMPONENT_WILL_UPDATE",
80+
},
81+
],
82+
},
83+
{
84+
code: dedent`
85+
import { Component } from "react";
86+
87+
class Foo extends Component {
88+
89+
componentWillUpdate() {}
90+
91+
render() {
92+
return <div />;
93+
}
94+
}
95+
`,
96+
errors: [
97+
{
98+
messageId: "NO_COMPONENT_WILL_UPDATE",
99+
},
100+
],
101+
},
102+
{
103+
code: dedent`
104+
import { PureComponent } from "react";
105+
106+
class Foo extends PureComponent {
107+
108+
componentWillUpdate() {}
109+
110+
render() {
111+
return <div />;
112+
}
113+
}
114+
`,
115+
errors: [
116+
{
117+
messageId: "NO_COMPONENT_WILL_UPDATE",
118+
},
119+
],
120+
},
121+
],
122+
});
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { isOneOf, NodeType } from "@eslint-react/ast";
2+
import { componentCollectorLegacy } from "@eslint-react/core";
3+
import { E } from "@eslint-react/tools";
4+
import type { TSESTree } from "@typescript-eslint/utils";
5+
import { ESLintUtils } from "@typescript-eslint/utils";
6+
import type { ConstantCase } from "string-ts";
7+
8+
import { createRule } from "../utils";
9+
10+
export const RULE_NAME = "no-component-will-update";
11+
12+
export type MessageID = ConstantCase<typeof RULE_NAME>;
13+
14+
function isComponentWillUpdate(node: TSESTree.ClassElement) {
15+
return isOneOf([NodeType.MethodDefinition, NodeType.PropertyDefinition])(node)
16+
&& node.key.type === NodeType.Identifier
17+
&& node.key.name === "componentWillUpdate";
18+
}
19+
20+
export default createRule<[], MessageID>({
21+
name: RULE_NAME,
22+
meta: {
23+
type: "problem",
24+
docs: {
25+
description: "disallow usage of `componentWillUpdate`",
26+
recommended: "recommended",
27+
requiresTypeChecking: false,
28+
},
29+
schema: [],
30+
messages: {
31+
NO_COMPONENT_WILL_UPDATE: "Do not use `componentWillUpdate`.",
32+
},
33+
},
34+
defaultOptions: [],
35+
create(context) {
36+
const { ctx, listeners } = componentCollectorLegacy(context);
37+
38+
return {
39+
...listeners,
40+
"Program:exit"() {
41+
const maybeComponents = ctx.getAllComponents();
42+
if (E.isLeft(maybeComponents)) {
43+
return;
44+
}
45+
const components = maybeComponents.right;
46+
47+
for (const { node: component } of components.values()) {
48+
const { body } = component.body;
49+
50+
for (const member of body) {
51+
if (isComponentWillUpdate(member)) {
52+
context.report({
53+
messageId: "NO_COMPONENT_WILL_UPDATE",
54+
node: member,
55+
});
56+
}
57+
}
58+
}
59+
},
60+
};
61+
},
62+
});

packages/eslint-plugin-react/src/rules/no-component-will-update.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Prevents usage of `componentWillUpdate` in class components.
1010

1111
## Why is this bad?
1212

13-
This API has been renamed from componentWillMount to UNSAFE_componentWillMount. The old name has been deprecated. In a future major version of React, only the new name will work.
13+
This API has been renamed from `componentWillUpdate` to `UNSAFE_componentWillUpdate`. The old name has been deprecated. In a future major version of React, only the new name will work.
1414

1515
Run the [rename-unsafe-lifecycles codemod](https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles) to automatically update your components.
1616

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# react/no-unsafe-component-will-receive-props
2+
3+
## Rule category
4+
5+
Suspicious.
6+
7+
## What it does
8+
9+
Warns usage of `UNSAFE_componentWillReceiveProps` in class components.
10+
11+
## Why is this bad?
12+
13+
Using unsafe lifecycle methods like `UNSAFE_componentWillReceiveProps` makes your component's behavior less predictable and are more likely to cause bugs.
14+
15+
## Examples
16+
17+
### ❌ Incorrect
18+
19+
```tsx
20+
import React from "react";
21+
22+
class MyComponent extends React.Component {
23+
UNSAFE_componentWillReceiveProps() {
24+
// ...
25+
}
26+
}
27+
```

0 commit comments

Comments
 (0)