Skip to content

Commit ed7fbcc

Browse files
authored
fix: hooks-extra/prefer-use-state-lazy-initialization false positive on useState(use(promise)) closes #999 (#1000)
1 parent 05bf6a1 commit ed7fbcc

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

packages/plugins/eslint-plugin-react-hooks-extra/src/rules/prefer-use-state-lazy-initialization.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,27 @@ ruleTester.run(RULE_NAME, rule, {
260260
'const { useState } = require("react"); useState(1 < 2 ? 3 : 4)',
261261
'const { useState } = require("react"); useState(1 == 2 ? 3 : 4)',
262262
'const { useState } = require("react"); useState(1 === 2 ? 3 : 4)',
263+
"const [state, setState] = useState(use(promise));",
264+
{
265+
code: tsx`
266+
import { useState, use } from 'react';
267+
268+
const promise = Promise.resolve();
269+
270+
function App() {
271+
const [state, setState] = useState(use(promise));
272+
273+
return null;
274+
}
275+
276+
export default App;
277+
`,
278+
settings: {
279+
"react-x": {
280+
version: "19.0.0",
281+
},
282+
},
283+
},
263284
{
264285
code: "useLocalStorageState()",
265286
settings: {

packages/plugins/eslint-plugin-react-hooks-extra/src/rules/prefer-use-state-lazy-initialization.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Ported from https://github.com/jsx-eslint/eslint-plugin-react/pull/3579/commits/ebb739a0fe99a2ee77055870bfda9f67a2691374
22
import * as AST from "@eslint-react/ast";
3-
import { isReactHookCall, isReactHookCallWithNameLoose, isUseStateCall } from "@eslint-react/core";
3+
import { isReactHookCall, isReactHookCallWithNameLoose, isReactHookName, isUseStateCall } from "@eslint-react/core";
44
import type { RuleContext, RuleFeature } from "@eslint-react/shared";
55
import { getSettingsFromContext } from "@eslint-react/shared";
66
import type { RuleListener } from "@typescript-eslint/utils/ts-eslint";
@@ -14,8 +14,16 @@ export const RULE_FEATURES = [] as const satisfies RuleFeature[];
1414

1515
export type MessageID = CamelCase<typeof RULE_NAME>;
1616

17-
// variables should be defined here
18-
const ALLOW_LIST = ["Boolean", "String", "Number"];
17+
// identifier names for allowed function names
18+
const ALLOW_LIST = [
19+
"Boolean",
20+
"String",
21+
"Number",
22+
];
23+
24+
function isAllowedName(name: string): boolean {
25+
return ALLOW_LIST.includes(name) || isReactHookName(name);
26+
}
1927

2028
// rule takes inspiration from https://github.com/facebook/react/issues/26520
2129
export default createRule<[], MessageID>({
@@ -54,11 +62,11 @@ export function create(context: RuleContext<MessageID, []>): RuleListener {
5462
const nestedCallExpressions = AST.getNestedCallExpressions(useStateInput);
5563
const hasFunctionCall = nestedCallExpressions.some((n) => {
5664
return "name" in n.callee
57-
&& !ALLOW_LIST.includes(n.callee.name);
65+
&& !isAllowedName(n.callee.name);
5866
});
5967
const hasNewCall = AST.getNestedNewExpressions(useStateInput).some((n) => {
6068
return "name" in n.callee
61-
&& !ALLOW_LIST.includes(n.callee.name);
69+
&& !isAllowedName(n.callee.name);
6270
});
6371
if (!hasFunctionCall && !hasNewCall) {
6472
return;

0 commit comments

Comments
 (0)