Maximizing Performance with the useCallback Hook in React

Maximizing Performance with the useCallback Hook in React

·

4 min read

Ever wondered why some complex web applications are slow in rendering their components? There can be a few reasons for this, of which, one major reason is due to unnecessary renders of functions thus reducing the time required to render our DOM.

However, React helps solve this problem with the help of the useCallback hook.

What is the useCallback hook?

React's useCallback hook is that which enables one to improve component performance by only re-rendering them when specific values change.

This is particularly helpful when only a tiny percentage of the props in your component are actually changing but it is being repeatedly displayed.

It returns a memoized version of the callback function that only alters if a dependent variable has changed.

Before delving deep into the useCallback hook, let's first understand the problem this hook solves - REFERENTIAL EQUALITY.

What is referential equality?

JavaScript treats functions as first-class citizens, making them ordinary objects.

The function object can be compared, returned by other functions, and used in any way that an object can be used.

When two values are objects that both point to the same address in memory, they are regarded as being equal. Thus, we can say the objects are referentially equal.

Let's write a function findValue that returns functions that multiply numbers and pass arguments into them:

const multiplyNumber = (a,b) => {
    return a * b
}

const functionOne = findValue();
const functionTwo = findValue();

functionOne(2,3);
functionTwo(3,2);

The above code snippet should return 6 for both instances, now lets perform a referential check on both and on one then log out the responses.

console.log(functionOne === functionTwo) // returns false;

console.log( functionOne === functionOne) // returns true;

console.log( functionTwo === functionTwo) // returns true;

So, why this behaviour? . It's exactly as I stated earlier, functions are objects, though both functions share a common source code, they are different objects because different memory and addresses have been assigned to them!.

And since JavaScript sees the functions as different though the same, they get re-rendered everytime thus reducing optimization.

Here's where the useCallback hook comes to the rescue. Yay!

How does useCallback works?

It works by "monitoring" a dependent variable in a function, such that whenever the state of that variable changes , only then a function is rendered.

Basically, there are two ways we can use the useCallback hook,

i. By passing the dependency as a property into the callback function.

ii. Having a component that receives the callback function as a property.

Here below is one way of using this hook passing the dependency as a property into the callback function .

e.g

import { useCallback } from 'react';

function MyComponent({ props }) {
  const handleClick = useCallback(() => {
    console.log('Button was clicked!');
  }, [props]);

  return (
    <button onClick={handleClick}>
      Click me!
    </button>
  );
}

In the illustration above, the useCallback hook is being used to create a handleClick function that will only be recreated if the props prop changes.

As a result, the handleClick function won't be created if the component is repeatedly rendered but the value of props stays the same.

When a parent component is frequently re-rendering but the props being passed to the child component are not changing, this can be especially helpful.

In this scenario, the child component won't needlessly re-render, which can enhance the overall performance of your application.

ii. When you have a component that accepts a callback function as a prop but want to make sure that the callback function is only created once and not recreated every time the component re-renders, you can also use the useCallback method.

import { useCallback } from 'react';

function Parent() {
  const handleClick = useCallback(() => {
    console.log('Button was clicked!');
  }, []);

  return (
    <Child handleClick={handleClick} />
  );
}

function Child({ handleClick }) {
  return (
    <button onClick={handleClick}>
      Click me!
    </button>
  );
}

In this illustration, the parent component's initial rendering is the only time the handleClick function is constructed. It is then supplied as a prop to the child component.

The handleClick method won't be regenerated, and the Child component won't need to render again even if the Parent component does so again.

In conclusion, the powerful hook useCallback can help you optimize the efficiency of your React components by only re-rendering them when specific values change.

When working with callback functions that are supplied as props or when a component is often re-rendered but just some of its props are changing, it is extremely helpful.

Conclusion

And that sums up this hook!. Thanks for reading this article. I hope it has been useful for React newbies.

Questions are welcome in the comments section below.

Ultimately, anyone may learn this hook more quickly by practicing and constructing projects with it.

Byeee😉👋