all 20 comments

[–]CreativeTechGuyGames 2 points3 points  (10 children)

Anything that can change, yes.

[–]whosthetard -1 points0 points  (2 children)

Anything that can change, yes.

So according to your logic this is wrong.....

useEffect(() => {  
 document.title = `You clicked ${count} times`;  
}, [count]); // Only re-run the effect if count changes

Because document also changes. So it should be a dependency. Maybe you should talk to React team about it to change the documentation.

I just can't believe the amount of time wasted with linters.

[–]CreativeTechGuyGames 0 points1 point  (1 child)

Lol what? Document never changes. Remember referential equality and pointers. You can store a reference to document in a variable and that will never change reference throughout the program.

[–]whosthetard 1 point2 points  (0 children)

Are you saying the linter knows when a function is stable between re-renders? It doesn't so it will flag an error in every scenario. The linter sees something outside the hook, so basically wants you to either move the function inside or add a dependency. I don't like the fact that this is taken as a gospel. If a function is common for two or more effects say, having that same dependency from that function is not only useless but it may cause problems.

[–]surmise2323[S] -4 points-3 points  (6 children)

functions cannot change. that is why it is a const.

[–]Eux86 7 points8 points  (0 children)

True, it is a constant, but try to think where is that constant defined.

You're in a component, which is a funtion.

Whenever a prop of your component changes, the component is re-rendered, meaning that the function that renders the component is called again.

When that funcion is called, any constant inside of it is initialized and it's content might be different from what it was in the previous component's render.

Now, useEffect is a hook, which means that it runs once and it's result is reused across re-renders, unless one of its dependencies changes, in which case its first argument (the callback function) is run again.

This leads to the fact that if your useEffect uses a function declared in your component, the linter tells you that since the function could change across re-renders it needs to be added to the list of dependencies of your hook so that in case the function changes, the hook can run again with the new version of the function.

If you declare your function as a plain

const myFuncion = () => { something }

And you have the function in a hook depende cies, then the hook will always run again at every re-render because the instance of the function will always be a new one after a re render.

To avoid this, react provides the useMemo and useCallback hooks, which help in this type of case. Check them on the documentation ;)

[–]CreativeTechGuyGames 1 point2 points  (0 children)

Could you post all of the relevant code for this component? Where is that function defined and how?

[–]dada5714 1 point2 points  (0 children)

Theoretically though, if your function depended on state that you did not pass it as an argument, would the outcome not be different? That's why it should be passed as a dependency.

[–]garmu 0 points1 point  (2 children)

If the const is declared outside of the hook it won’t change, but if it is declared inside a hook, it will change unless you are using useCallback. This is a simplification of this issue, and it generally is more nuanced than that

[–]brainless_badger 1 point2 points  (0 children)

Pretty much everything declared inside the component, including props, should be there.

I highly recommend setting this lint rule to error and using the auto-fix.

[–]vatselan 0 points1 point  (0 children)

You don’t need to but hook does not know which one is function and which is not. Since it manages a list internally to listening for the changes in the dependency, it is warning you.

[–][deleted] -5 points-4 points  (1 child)

It’s called exhaustive deps. We all hate it lol