Understanding Referential Equality in React

What is Referential Equality?

In JavaScript, you can compare two values using the identity operator (===). For primitive data types, the comparison is made using actual values. However, for complex values like objects and functions, the comparison is made using references. Two functions are not equal, even if they have the same code.


const func1 = () => console.log('Hello');
const func2 = () => console.log('Hello');

console.log(func1 === func2); // false

Why is Referential Equality Important in React?

In React, understanding referential equality is vital because we often create different functions with the same code. When a component re-renders, React destroys the current version of the function and creates a new one. This approach can be inefficient, especially when using Hooks like useEffect or memoized components.

The Problem with useCallback

One solution to this problem is to use the useCallback Hook, which memoizes the function. However, when the event handler depends on a state or prop, the useCallback Hook creates a new handler function each time it changes.


import { useState, useCallback } from 'react';

function Example() {
  const [count, setCount] = useState(0);
  const handleClick = useCallback(() => {
    console.log(count);
  }, [count]);

  return (


  );
}

Introducing the useEvent Hook

The useEvent Hook solves this problem by defining an event handler with a stable function identity. The event handler will not be recreated each time a prop or state changes, and it will have access to the latest value of both the prop and state.

Implementing the useEvent Hook

The useEvent Hook is called with each render of the component where it is used. Inside the useEvent Hook, the useLayoutEffect Hook is called with each render, and it changes the handlerRef to the latest values of the handler function.


import { useLayoutEffect, useRef } from 'react';

function useEvent(handler) {
  const handlerRef = useRef(handler);

  useLayoutEffect(() => {
    handlerRef.current = handler;
  }, [handler]);

  return handlerRef.current;
}

When Not to Use the useEvent Hook

There are certain situations where you shouldn’t use the useEvent Hook. For example, you can’t use functions created with the useEvent Hook during rendering. Additionally, the unmounting useEffect Hook and the useLayoutEffect Hook will have a different version of the useEvent handler.

  • Avoid using the useEvent Hook during rendering.
  • Be aware of the different versions of the useEvent handler in the unmounting useEffect Hook and the useLayoutEffect Hook.

Leave a Reply

Your email address will not be published. Required fields are marked *