Bug: [eslint-plugin-react-hooks] No `react-hooks/exhaustive-deps` warning when an unstable reference is passed to hook's callback parameter
React version: 19.1.0 eslint-plugin-react-hooks version: 5.2.0
Steps To Reproduce
-
git clone https://github.com/aweebit/eslint-plugin-react-hooks-unstable-reference-issue.git` cd eslint-plugin-react-hooks-unstable-reference-issue npm install - Run
npm run lintand observe how there are no warnings. - Run
npm start, open the served page in your browser and look at the console output.
Link to example repository: https://github.com/aweebit/eslint-plugin-react-hooks-unstable-reference-issue
Here is the full example code:
import { createElement, useEffect, useReducer } from "react";
import { createRoot } from "react-dom/client";
let bar = () => console.log("good");
function Example() {
console.log("rendering");
const [updateTrigger, triggerUpdate] = useReducer(() => ({}), {});
useEffect(() => {
const timeout = setTimeout(triggerUpdate);
return () => clearTimeout(timeout);
}, []);
useEffect(bar, [updateTrigger]);
return null;
}
createRoot(
/** @type {HTMLDivElement} */ (document.getElementById("root"))
).render(createElement(Example));
setTimeout(() =>
setTimeout(() => {
console.log("changing bar");
bar = () => console.log("evil");
})
);
The current behavior
No ESLint warnings
The expected behavior
15:3 warning React Hook useEffect received a function whose dependencies are unknown. Pass an inline function instead react-hooks/exhaustive-deps
Details
The expected behavior is what happens if you write
const foo = { bar: () => console.log("good") };
and replace bar with foo.bar everywhere.
The warning makes perfect sense since there is no way for the linter plugin to know for sure foo.bar doesn't change between renders. But there is also no way for it to know it if a variable declared with let such as bar is passed! That's why a warning also has to be produced in that case.
On the other hand, if the variable passed was declared with const, it is fine to not produce any warning because in that case, the plugin would have a guarantee it's a stable reference.
The issue was discovered in https://github.com/facebook/react/issues/31207#issuecomment-2925440287.
I want to use the opportunity and encourage everybody reading to have a look at #33041 and join in for a discussion. The issue has been completely ignored so far, which is unfortunate considering how often I run into situations where I really wish the functionality proposed there was provided by React itself. Happens pretty much in every project I work on.
Hi is this issue open? I would like to contribute please assign it to me
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Bump