In React Typescript with the exhaustive-deps rule enabled, when I define a ref and use that inside of an effect, the linter is fine with it:
const stringRef: RefObject<string> = useRef("Hello World!");
useEffect(() => {
console.log(stringRef.current);
}, []) // no warning, the linter detects that I'm using a ref
However, when I put the effect inside of a custom hook, the linter complains that I should include the ref inside of the dependency array:
const stringRef: RefObject<string> = useRef("Hello World!");
useCustomHook(stringRef);
// in another-file.ts
const useCustomHook = (ref: RefObject<string>) => {
useEffect(() => {
console.log(ref.current);
}, []) // ESLint: React Hook useEffect has a missing dependency: 'ref'. Either include it or remove the dependency array.(react-hooks/exhaustive-deps)
}
Semantically, nothing changed, however, the linter doesn't recognize that ref is a RefObject (even though I typed it as such).
The big question now is: How can I make the linter know that the given dependency doesn't need to be included in the dependency array without suppressing the warning?
For me, it's a major drawback that this is not possible, because I can't convert my effects into custom hooks without the linter complaining.
Thanks for your help.
The warning "React Hook useEffect has a missing dependency" occurs when the useEffect hook makes use of a variable or function that we haven't included in its dependencies array. To solve the error, disable the rule for a line or move the variable inside the useEffect hook.
useEffect has an unnecessary dependency: 'log'. aren't valid dependencies because mutating them doesn't re-render the component. This is because even if I did reassign that log variable to something else at some point, React wouldn't know about it so you'd end up with a stale side-effect anyway.
Placing useEffect inside the component lets us access the count state variable (or any props) right from the effect. We don't need a special API to read it — it's already in the function scope. Hooks embrace JavaScript closures and avoid introducing React-specific APIs where JavaScript already provides a solution.
In the useEffect , we are updating the useRef current value each time the inputValue is updated by entering text into the input field.
You can't configure it out of the box.
The linter (eslint
) is a static code analyzer. It only analyzes text patterns without compiling the code, i.e it doesn't know the "meaning" of what is written.
For example, it sees the "use***()
" pattern and believes its a custom hook, then it verifies it with Rules of Hooks patterns like not having such text in if
statement.
See for yourself:
Reminder: Custom hook is a function with 'use' prefix and a function which uses hooks.
// NOT A CUSTOM HOOK, just a function with 'use' prefix
const useConsole = () => console.log("hello");
// Normal function
const logHello = () => console.log("hello2");
const Component = () => {
if (true) {
// Warning - React hook is called conditionally
useConsole();
// OK
logHello();
}
return <>Example</>;
};
But, you always can propose a custom rule to identify RefObject<string>
and useEffect
in same scope.
From the Typescript compiler side, it doesn't violate anything as the use case matches the useEffect
type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With