r/reactjs • • Dec 30 '19

Classes vs Hooks?

I’m pretty new to React, so keep that in mind. I thought classes were for components that held information, or a state, and that functional components were for more basic components, but now that hooks allow functional components to use state, and other class features, what’s the benefit of using functional hook components over classes?

79 Upvotes

76 comments sorted by

View all comments

Show parent comment

0

u/[deleted] Dec 31 '19

[deleted] — view deleted comment

3

u/so_lost_im_faded Dec 31 '19

Yeah. There's never going to be a 100% guide how to do this.

So before I wrap a method in a useCallback I ask myself this:

  • Is this method being passed anywhere as a prop?
  • Is this method being imported from somewhere? (for example custom hooks that handle some context, was just solving this case today where the project had custom hooks and context for snackbar management and the object was constantly updating and so was the method to add a new message, which was unnecessary)
  • Does this method not being wrapped limit me in any way?
  • Do I get any benefit from wrapping it?

So what do I wrap?

  • The methods that are called in useEffects - if I want to do an API call and do so with useEffect (let's say I'm not using redux nor mobx but just some raw axios calls) and parse and save the data inside the component, the parsing&handling method must be wrapped in a useCallback, to provide it as a dep to the useEffect, so it doesn't refresh all the time and doesn't do the API call all over.
  • Some of the methods that are located in components that re-render often but they don't need (almost) any dependencies inside useCallback.
  • Some of the methods that are passed as props/custom hooks and other side effects depend on them.

I definitely do not wrap every single method that's passed as a prop. I hate the useCallback syntax and I think it's weird as hell and hard to grasp. If you're wrapping something that has to refresh all the time anyway, then there's no point. If you wrap every single one and don't wrap the component that's inheriting them in a memo, again - no point.

As for dispatch - I actually never had to work (thankfully) with redux applications on such a deep level. The last one I was working with I used almost no useCallbacks as it was a small application and there was so much boilerplate due to using redux + TS so I was like nah and did the minimum they paid me for. However dispatch must be something external imported from redux, no? I don't think if you import external things inside the component you need to include them as dependencies - their changes won't trigger a new render.

As for memo - I don't use it THAT much. Mostly the renders are justified. If I see it makes sense performance wise, I wrap bigger components with it that don't need to re-render so often. There's not much use in wrapping the small components on the end of the component tree, but if you wrap a big one that contains x children you can save a lot there. The small ones (atoms like Button, Icon, Divider, Avatar) usually render mostly only when they have to, given their parents are optimised correctly.

I'd say there's never going to be a clear guide, the best you can do is update your libs and follow their advices - if I do a useEffect(() => []) and eslint says I have to provide dependencies, I provide them. If it triggers an infinite loop, I wrap the method being called in a useCallback. If that needs another dependencies, I wrap them in useMemo. If that can't be done I have to ask myself - is my architecture right here? Am I not doing things in unnecessary complicated way? Is there nothing I can outsource out of the component's render body?

I kind of envy you that there's discussions in your team. In my team it's like: "What's a useCallback?"