react
react copied to clipboard
Bug: react-hooks/exhaustive-deps false positive when use function with generic type variable in useEffect
React version: 18.2.0
Steps To Reproduce
- use function with generic type in useEffect
code example:
function useBug<T>(val: T) {
const ref = useRef<T>(val)
const fn = () => {
const temp: T = ref.current // <-- if remove the generic type will be ok
}
useEffect(() => {
fn()
}, []) // <-- ESLint error: React Hook useEffect has a missing dependency: 'fn'.
}
package version:
npmPackages:
@typescript-eslint/eslint-plugin: ^5.35.1 => 5.35.1
@typescript-eslint/parser: ^5.35.1 => 5.35.1
@typescript-eslint/scope-manager: 5.35.1
@typescript-eslint/type-utils: 5.35.1
@typescript-eslint/types: 5.35.1
@typescript-eslint/typescript-estree: 5.35.1
@typescript-eslint/utils: 5.35.1
@typescript-eslint/visitor-keys: 5.35.1
eslint: ^8.23.0 => 8.23.0
eslint-plugin-react-hooks: ^4.6.0 => 4.6.0
relevant: #20395
The current behavior
React Hook useEffect has a missing dependency: 'fn'. Either include it or remove the dependency array.
The expected behavior
No missing dependencies reported.
Had this bug too in my application
But fn
is missing. I don't get any different behavior when removing T
.
What is producing a false-positive is
useEffect(() => {
const fn = () => {
const temp: T = ref.current
}
fn()
}, []) // <-- ESLint error: React Hook useEffect has a missing dependency: 'T'.
which needs fixing
Another solution
function useBug<T>(val: T) {
const ref = useRef<T>(val)
const fn = useCallback(
() => {
const temp: T = ref.current // <-- if remove the generic type will be ok
},
[ref],
)
useEffect(() => {
fn()
}, [fn]) // <-- ESLint error: React Hook useEffect has a missing dependency: 'fn'.
}
Here's a better reproducible example:
import { useEffect, useState } from "react";
import "./styles.css";
function useTypedState<StateObject>(defaultValue: StateObject) {
const [val, setVal] = useState<StateObject>(defaultValue);
useEffect(() => {
console.log(val as StateObject);
}, [val]);
/*
^^^
React Hook useEffect has a missing dependency: 'StateObject'.
Either include it or remove the dependency array. (react-hooks/exhaustive-deps)eslint
*/
return [val, setVal] as const;
}
export default function App() {
const [count, setCount] = useTypedState<number>(0);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={() => setCount((c) => c + 1)}>{count}</button>
</div>
);
}