Skip to content

Commit 0f34ea3

Browse files
authored
fix(plugins/hooks-extra): fix call and new expression related false positives in no-unnecessary-use-memo and no-unnecessary-use-callback (#895)
1 parent d802f3e commit 0f34ea3

File tree

22 files changed

+102
-402
lines changed

22 files changed

+102
-402
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44

55
- refactor: JSX fragments related rules no longer rely on `jsxPragma` and `jsxFragmentPragma` settings to perform their checks
66
- refactor: improve applicability of the `no-useless-fragment` and `prefer-shorthand-fragment` rules
7-
- refactor: deprecate `settings["react-x"].jsxPragma` and `settings["react-x"].jsxFragmentPragma`
7+
- refactor: deprecate `settings["react-x"].jsxPragma` and `settings["react-x"].jsxFragmentPragma` as they are no longer needed by any rules
8+
9+
### 🐞 Fixes
10+
11+
- fix(plugins/hooks-extra): fix `call` and `new` expression related false positives in `no-unnecessary-use-memo` and `no-unnecessary-use-callback`
812

913
## v1.22.2 (Mon 30 Dec 2024)
1014

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.23.0-beta.0
1+
1.23.0-next.1

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@eslint-react/monorepo",
3-
"version": "1.23.0-beta.0",
3+
"version": "1.23.0-next.1",
44
"private": true,
55
"description": "Monorepo for eslint-plugin-react-[x, dom, web-api, hooks-extra, naming-convention].",
66
"keywords": [

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@eslint-react/core",
3-
"version": "1.23.0-beta.0",
3+
"version": "1.23.0-next.1",
44
"description": "ESLint React's ESLint utility module for static analysis of React core APIs and Patterns.",
55
"homepage": "https://github.com/rEl1cx/eslint-react",
66
"bugs": {

packages/plugins/eslint-plugin-react-debug/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "eslint-plugin-react-debug",
3-
"version": "1.23.0-beta.0",
3+
"version": "1.23.0-next.1",
44
"description": "ESLint React's ESLint plugin for debugging related rules.",
55
"keywords": [
66
"react",

packages/plugins/eslint-plugin-react-debug/src/rules/function-component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default createRule<[], MessageID>({
2323
},
2424
messages: {
2525
functionComponent:
26-
"[function component] name: {{name}}, memo: {{memo}}, forwardRef: {{forwardRef}}, hookCalls: {{hookCalls}}",
26+
"[function component] name: {{name}}, memo: {{memo}}, forwardRef: {{forwardRef}}, hookCalls: {{hookCalls}}.",
2727
},
2828
schema: [],
2929
},

packages/plugins/eslint-plugin-react-dom/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "eslint-plugin-react-dom",
3-
"version": "1.23.0-beta.0",
3+
"version": "1.23.0-next.1",
44
"description": "ESLint React's ESLint plugin for React DOM related rules.",
55
"keywords": [
66
"react",

packages/plugins/eslint-plugin-react-hooks-extra/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "eslint-plugin-react-hooks-extra",
3-
"version": "1.23.0-beta.0",
3+
"version": "1.23.0-next.1",
44
"description": "ESLint React's ESLint plugin for React Hooks related rules.",
55
"keywords": [
66
"react",

packages/plugins/eslint-plugin-react-hooks-extra/src/rules/no-unnecessary-use-callback.spec.ts

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,40 @@ import rule, { RULE_NAME } from "./no-unnecessary-use-callback";
44
// TODO: Add more tests
55
ruleTester.run(RULE_NAME, rule, {
66
invalid: [
7+
{
8+
code: /* tsx */ `
9+
import { useState, useCallback } from "react";
10+
11+
function MyComponent() {
12+
const a = 1;
13+
const handleSnapshot = useCallback(() => Number(1), []);
14+
15+
return null;
16+
}
17+
`,
18+
errors: [
19+
{
20+
messageId: "noUnnecessaryUseCallback",
21+
},
22+
],
23+
},
24+
{
25+
code: /* tsx */ `
26+
import { useState, useCallback } from "react";
27+
28+
function MyComponent() {
29+
const a = 1;
30+
const handleSnapshot = useCallback(() => new String("1"), []);
31+
32+
return null;
33+
}
34+
`,
35+
errors: [
36+
{
37+
messageId: "noUnnecessaryUseCallback",
38+
},
39+
],
40+
},
741
{
842
code: /* tsx */ `
943
import { useCallback } from "react";
@@ -79,25 +113,6 @@ ruleTester.run(RULE_NAME, rule, {
79113
},
80114
],
81115
},
82-
{
83-
code: /* tsx */ `
84-
import { useCallback } from "react";
85-
86-
const Comp = () => {
87-
const style = useCallback((theme) => ({
88-
input: {
89-
fontFamily: theme.fontFamilyMonospace
90-
}
91-
}));
92-
return <Button sx={style} />
93-
}
94-
`,
95-
errors: [
96-
{
97-
messageId: "noUnnecessaryUseCallback",
98-
},
99-
],
100-
},
101116
{
102117
code: /* tsx */ `
103118
const { useCallback } = require("react");

packages/plugins/eslint-plugin-react-hooks-extra/src/rules/no-unnecessary-use-callback.ts

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,10 @@ export default createRule<[], MessageID>({
4343
const scope = context.sourceCode.getScope(node);
4444
const component = scope.block;
4545
if (!AST.isFunction(component)) return;
46-
const [cb, deps] = node.arguments;
47-
if (!deps) {
48-
context.report({
49-
messageId: "noUnnecessaryUseCallback",
50-
node,
51-
});
52-
return;
53-
}
46+
const [arg0, arg1] = node.arguments;
47+
if (!arg0 || !arg1) return;
5448
const hasEmptyDeps = F.pipe(
55-
match(deps)
49+
match(arg1)
5650
.with({ type: AST_NODE_TYPES.ArrayExpression }, O.some)
5751
.with({ type: AST_NODE_TYPES.Identifier }, n => {
5852
return F.pipe(
@@ -65,15 +59,8 @@ export default createRule<[], MessageID>({
6559
O.exists(x => x.elements.length === 0),
6660
);
6761
if (!hasEmptyDeps) return;
68-
if (!cb) {
69-
context.report({
70-
messageId: "noUnnecessaryUseCallback",
71-
node,
72-
});
73-
return;
74-
}
7562
const isReferencedToComponentScope = F.pipe(
76-
match(cb)
63+
match(arg0)
7764
.with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, n => {
7865
if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) {
7966
return O.some(n.body);
@@ -93,11 +80,12 @@ export default createRule<[], MessageID>({
9380
O.map(s => VAR.getChidScopes(s).flatMap(x => x.references)),
9481
O.exists(refs => refs.some(x => x.resolved?.scope.block === component)),
9582
);
96-
if (isReferencedToComponentScope) return;
97-
context.report({
98-
messageId: "noUnnecessaryUseCallback",
99-
node,
100-
});
83+
if (!isReferencedToComponentScope) {
84+
context.report({
85+
messageId: "noUnnecessaryUseCallback",
86+
node,
87+
});
88+
}
10189
},
10290
};
10391
},

0 commit comments

Comments
 (0)