DEV Community

Cover image for How to write more performant functional React Components
Blake Wight
Blake Wight

Posted on

How to write more performant functional React Components

What are you on about?

When writing React with hooks, I've seen a lot of properties of functional components go un-memoized. In my opinion, this is almost always a no-no.

This is generally not a good practice because of how React works. Anything that is not memoized is redefined on every re-render. So in general, my rule is to memoize everything defined in the functional component and move everything else out of the component into the global scope.

Not only does this speed up the performance of the thing that you defined, but not doing this has a compounding effect. If the thing you forgot to memoize is depended on (meaning in the dependency array of useMemo or useCallback) by another property, that property will be redefined on every render as well.

Variables that are defined globally do not get redefined when re-renders happen so they can be used without worrying about causing redefinitions.

Say what?

Here is a nice before example from a personal project (ignore what is/isn't defined as far as imports):

const { Title } = Typography;

const UserScreen = () => {
  const db = firebaseApp.firestore();
  const { user, logout } = useContext(AuthContext);

  const onSubmit =
    async (newUserProperties) => {
      return await db
        .collection(DB.COLLECTIONS.USERS)
        .doc(user.uid)
        .update(newUserProperties);
    }

  return (...);
};

In this case, the firebaseApp.firestore() operation would be called on every render. Not fun. And then even if we threw the onSubmit function in a useCallback with db in the dependency array, that would be redefined on every render as well. So you don't even get credit for almost doing it right!

Prove it

Here is a codesandbox that illustrates my point: https://codesandbox.io/s/relaxed-pasteur-7spqq?file=/src/App.js

Photo by Max Frajer on Unsplash

Discussion (5)

Collapse
stereoplegic profile image
Mike Bybee

I'm gonna have to disagree. That's premature optimization, and potentially a cure worse than the disease in terms of memory overhead. Reach for useMemo and/or useCallback when rerenders are causing perf issues, and look to things like more localized context (if you're using it), offloading expensive computations to web workers, etc. first.

Collapse
stereoplegic profile image
Mike Bybee

The Kent C. Dodds article @exclipy shared is an excellent resource, BTW.

Collapse
exclipy profile image
exclipy

On your codesandbox: you should remove the useCallback. It's not doing anything but overhead.

Collapse
maxgrafx profile image
maxgrafx

i would think not using useCallback creates overhead, without it every render the function is recreated

Collapse
exclipy profile image
exclipy

Also with it, the function is created on every render. See kentcdodds.com/blog/usememo-and-us...