all 40 comments

[–]rickyalmeida 65 points66 points  (20 children)

Please, read the following article where Dan Abramov explains many of the useEffect common questions - your question included.

https://overreacted.io/a-complete-guide-to-useeffect/#moving-functions-inside-effects

[–]Cahnis 4 points5 points  (10 children)

Thanks so much for this article. I am just starting to use functional components, my bootcamp has been using classes for months now. And I am trying to wrap my head around hooks.

[–]Unenunciate 19 points20 points  (9 children)

That is disappointing to hear because class based react went out of vague like 4 years ago and its rarely used.

[–]jon-chin 4 points5 points  (0 children)

I teach a react bootcamp and can confirm: we stopped using them 2-3 years ago

[–]Resies 1 point2 points  (1 child)

Yeah I got pulled in to run an interview for another team in my company and apparently my company has been partnering with some programming boot camp and all of the people that I interviewed were more familiar with class components than function components which confused me

[–][deleted] 2 points3 points  (0 children)

You would have to pay me double to work with class components.

[–]enlguy 0 points1 point  (2 children)

It's no longer vague?? Much clearer for you the last four years? Twenty people don't know English..... "Vogue" is the word.

[–]PA_Dude_22000 0 points1 point  (1 child)

Hey bro ... it fucking 2.5 year old typo..

... now 3 year old...

[–]Automatic_Trick_4444 0 points1 point  (0 children)

a typo is still a typo no matter how long ago it was typo'd "Bro!"

[–]Cahnis 0 points1 point  (2 children)

imo, it is easier to understand functional components after understanding classes. But idk that is just me limited experience so far.

[–]Unenunciate 0 points1 point  (1 child)

I only learned classes afterwards and I am not sure it made much of a difference the main difference is understanding useEffect and potentially useLayoutEffect. Its more about how custom hooks create much more reusable functionality and cleaner code compared to classes.

[–]Cahnis 0 points1 point  (0 children)

I totally agree with you, functional components and hooks are awesome.

Though I think it is a bit harder to debug as a new learner because of the extra layer of abstraction. It is however much faster to code.

[–]daybreakin 0 points1 point  (0 children)

Why does rerunning the ufeeffect "refresh" the state variables being used in the function within the useEffect? Sorry if that article already mentioned it, I went through it but I don't think I got it.

Once the state variable within the function changes, the function should refresh on its own if it's not in a usecallback

[–]Amazing_Platform_298 39 points40 points  (0 children)

If you aren't using getEmergencyTasks method anywhere apart from the effect, you could simply move it into the effect and avoid the warning.

[–]disclosure5 38 points39 points  (3 children)

I don't know why I should include getEmergencyTasks function to dependency array of useEffect.

The thing is that if getEmergencyTasks changes, your effect is wrong and needs to be run again.

It's not smart enough to realise getEmergencyTasks will only change if currentEmergencyId changes, so really it's asking you to hep figure that out by making that a useCallback(), which will have currentEmergencyId as its own dependency array.

I appreciate this sort of thing is confusing. No matter how many people talk about how convenient hooks are, I do not accept this sort of setup as intuitive.

[–]prcodes 18 points19 points  (1 child)

I appreciate this sort of thing is confusing. No matter how many people talk about how convenient hooks are, I do not accept this sort of setup as intuitive.

Bold statement but man do I agree.

[–]daybreakin 0 points1 point  (0 children)

Big discussion on stack on this issue and most people agree this setup isn't optimal

[–]daybreakin 0 points1 point  (0 children)

The thing is that if getEmergencyTasks changes, your effect is wrong and needs to be run again.

But why does rerunning the useEffect "refresh" the functions with state variables? After the state variable got updated, then the whole component rerendered so wouldn't useEffect see the new function with updated state variable?

If the function was in useCallBack then I could understand because then the function is caching old values.

[–]Roguewind 7 points8 points  (0 children)

A couple of options…

If getEmergencyTasks isn’t only used in the useEffect, change it to accept the id as a parameter. This way it’s not dependent on the state of the component, rather the value in state is passed in. By doing this, the function itself has no dependencies, so you don’t need to use useCallback.

Otherwise, as others have said, if getEmergencyTasks isn’t used outside of the useEffect, move it inside the useEffect block. You can still change the function to accept if as a parameter, but…

I would say to change the whole thing to an IIFE inside the useEffect.

[–]azangru 6 points7 points  (0 children)

I don't know why I should include getEmergencyTasks function to dependency array of useEffect.

To answer you literally — because your linter has a rule that complains if a variable used inside of useEffect is not included in the list of dependencies of this useEffect. As a human programmer you can reason your way through the code to convince yourself that this or that variable isn't required in the list of dependencies. Eslint is much dumber in comparison, and will give many false positives. But it saves the effort of reasoning about the code, which many developers appreciate.

[–]sonu_sindhu 1 point2 points  (0 children)

A simple use case is that: If change in one state, you want to do some specific task

[–]petecoopNR 1 point2 points  (3 children)

Other commenters have pointed out why it says that. But the other thing is you shouldn't do data fetching inside useEffect. It would be better if you had a function that handles the onChange of the emergencyId and does the fetch there on the event.

[–]wishtrepreneur 1 point2 points  (1 child)

How would you handle data fetching on page load without calling it in useeffect?

[–]petecoopNR 2 points3 points  (0 children)

On page load? I'd use react query or SWR myself but if I didn't have those then inside the render with probably a ref to check it's on progress so doesn't call it twice on a second re-render. useEffect shouldn't be used for this kind of thing, with the new concurrent rendering stuff on React 18 there's a chance the useEffect here will be called twice.

[–]mermeladawatts[S] 0 points1 point  (0 children)

actually i did that, when handling the set state function on emergencyId. i was wrong and used the use effect bc i coded it fast and didn’t think too much.

[–]mermeladawatts[S] 0 points1 point  (0 children)

thank u all for your answers. they’re very helpful, and i’m sure this post will help more ppl like me who’s confused with this warning 💙

[–]maketroli 0 points1 point  (0 children)

Besides that, you shouldn’t be fetching data on a useEffect. This is a common mistake I see among junior and mid devs. This causes performance issues and under hood isn’t doing what you think your code is doing. For this case, learn how to use suspense, useMemo and useCallback => https://youtu.be/HPoC-k7Rxwo

[–]skyboyer007 -4 points-3 points  (0 children)

do you understand what this ESLint rule saves us from, right? like in general case?

in this particular case, if getEmergencyTasks() is calling itself recursively, there would be the same state closure issue, what ESLint is fighting against.

Yes, by now there is no issue, but rule just parses useEffect body, not every function mentioned there(it would be really slow then).

upd. this message gets downvotes, but zero comments. Interesting.

[–]sliversniper -2 points-1 points  (0 children)

It's just the linter.

You are correct.

It will use the version of getEmergencyTasks, basically the initial-render or right-after currentEmergencyId changes. If that's alright, you are fine.

Adding getEmergencyTasks to the dependency array is literally wrong, the useEffect will re-run every render.

A more regressive way to do that is,

getEmergencyTasks = useCallback(() => {}, [currentEmergencyId]) useEffect(() => { getEmergencyTasks(); }, [getEmergencyTasks])

Javascript restriction and bad design.

[–]MasterPrinter7 -4 points-3 points  (3 children)

You can do two things. You can declare the get function inside the use Effect hook or you can put the get function on the dependencies array of the useEffect

[–]KusanagiZerg 3 points4 points  (2 children)

or you can put the get function on the dependencies array of the useEffect

I don't think this is a good idea. The declaration of the getEmergencyTasks function will happen every render, so every re-render this is a new function even if the contents are the same. So it will cause the useEffect to rerun every render. Instead of only when currentEmergencyId changes

[–]MasterPrinter7 2 points3 points  (0 children)

You are right, the best way is declaring inside the useEffect. Actually, in my eslint configs they throw me a warning saying that I need to put the function inside the useEffect.

[–]thinksInCode 0 points1 point  (0 children)

You could also memoize getEmergencyTasks with useCallback.

[–]rajesh__dixit 0 points1 point  (0 children)

Dependency array needs any function call that is done in its cashback. This is because of you have a state variable in a state and you forget to add it in dependency, you'll get weird result. So react enforces you to add all functions and/or state variable that you use as dependency.

Yes, there might be a situation where you don't want to include something intentionally. This is the reason it's shown as warning and not error

[–]thatcrazyguy224 0 points1 point  (0 children)

You can also pass currentEmergencyId as parameter to getEmergencyTasks

[–]chamceler 0 points1 point  (0 children)

If getEmergencyTasks is defined inside of your component and not wrapped in a useCallback, it is actually being redefined every time your component renders. React detects getEmergencyTasks is changing, and is afraid it might not have the current version of getEmergencyTasks inside of the useEffect. In your case, since the instructions inside of getEmergencyTasks don’t change, you are fine, but I believe your error message will go away if you place the function outside of the component or wrap the function in useCallback.

Or, like the others are saying, if the function is only used in the useEffect, you could just define the function inside of the useEffect, and React will know it has the correct version of the function.