5 ms·
"For example: you have a callback function declared as an expression, that the useEffect hook calls. The linter will say "oh this is an expression, therefore it
by cbovis 3y ago
"For example: you have a callback function declared as an expression, that the useEffect hook calls. The linter will say "oh this is an expression, therefore it needs to be declared as a dependency". But it doesn't, because looking at the code as a human, you can immediately see the function never changes."
Can you elaborate on this? In my experience this isn't the case. If a function is declared outside of the component scope then it won't trigger a lint error. If it's defined within the component scope and not wrapped in useCallback then it does in fact change on every render and the lint error is being raised for good reason.
- davedx 3y ago> If it's defined within the component scope and not wrapped in useCallback then it does in fact change on every render and the lint error is being raised for good reason. So I just did some playing around to investigate this further, and it seems to be more subtle than I thought. If you have a function expression but the expression is not dependent on any outer scoped variables, the linter does not complain that you didn't specify the function itself as a dependency in useEffect. Example: ``` let bar = "bar"; const setResult = (result: string) => { // Won't trigger "exhaustive-deps" setBio(result); // Will trigger "exhaustive-deps" if (bar === "1") setBio(result); }; useEffect(() => { setResult(""); }, [person]); ``` So there's some quite sophisticated analysis of the AST going on in the lint rule. I still think that this rule is too complicated for a linter. (Bugs like inter-dependencies in your data and code should be caught by unit tests). But it's technically pretty impressive. Edit: I did some more investigations. If I make a function that depends on something very unpure (like checking window.location), the linter fires if the unpure function is in the outer scope of the hook, but not if it isn't. Even though the dependency is the same. So the linter rule can only identify locally scoped dependencies I think.
- joshribakoff 3y ago> Bugs like inter-dependencies in your data and code should be caught by unit tests Why write a ton of unit tests for what a static check can just do “for free?”. Not sure i follow your logic. I agree React can feel like a nuisance, but the lint rule itself is not the issue i think you have, it sounds like your issue is just with hooks.
- Jcampuzano2 3y agoIts not necessarily that the function depends on something 'very unpure', its if it depends on anything which is non-primitive that is created or assigned within the component fn body. window.location returns a Location object which is not a primitive, and so it will trigger exhaustive deps if it is being used by way of a reference inside the component render function (assigned to a variable), since it could theoretically be a different object reference on subsequent renders. Since the linter can't necessarily tell if the reference has changed out from under it on subsequent renders due to the fact that it could be mutably changed, it marks it as a necessary dep.
- kajaktum 3y agoThis seems obvious to me? Your lambda captures an outside object that will change with each render pass?
- cush 3y agoI recommend you read the article again. Just because window.location changes outside scope doesn't mean that React would update the component when window.location changes just because you put it in a dependency array. This is because props or state didn't change and the parent didn't rerender. UseEffect dependencies aren't observables. You'd need to wire up an event listener on unload, hashChange, etc https://stackoverflow.com/questions/58442168/why-useeffect-doesnt-run-on-window-location-pathname-changes#58443076 https://stackoverflow.com/questions/58442168/why-useeffect-d...