Skip to content

Referential Equality Mistake with React's useEffect

Posted on:June 19, 2023

We’ll explore a practical example, dissect the issue, and demonstrate a solution using the useMemo hook.

Table of contents

Open Table of contents

The Setup

Let’s consider a straightforward form component with three state variables: age, name, and darkMode. The component renders inputs for each variable, and a useEffect hook is in place to log the current person whenever either age or name changes.

const [age, setAge] = useState(0);
const [name, setName] = useState("");
const [darkMode, setDarkMode] = useState(false);

const person = { age, name };

useEffect(() => {
  console.log(person);
}, [person]);

return; // Here goes JSX with your form

However, there’s an unexpected behavior when toggling the darkMode checkbox. Upon inspecting the console, we notice that toggling darkMode triggers the useEffect even though neither age nor name is changing. To unravel this mystery, we must understand referential equality.

Referential Equality Explained

Referential equality in JavaScript implies that two objects are considered equal only if they reference the exact same object in memory. Even if two objects have identical properties, they are not equal if they are distinct instances.

In our form component, the issue arises because, on every re-render, a new person object is created. Although the properties (age and name) may remain the same, the objects themselves are different. As a result, the useEffect hook, which relies on referential equality, incorrectly perceives a change in the person object.

To address this, we employ the useMemo hook. By wrapping the person object in useMemo, we ensure that a new object is returned only when age or name changes. This prevents unnecessary re-renders triggered by the creation of a new object during each render cycle.

const person = useMemo(() => {
  return { age, name };
}, [age, name]);

Now, the useEffect hook will only be invoked when there’s an actual change in the age or name properties, eliminating the unexpected logging caused by referential inequality.

Conclusion

Understanding referential equality is pivotal in React development, especially when working with hooks like useEffect. By recognizing scenarios where new object instances are created unnecessarily, developers can employ tools like useMemo to optimize performance and avoid unintended side effects. This nuanced understanding enhances code reliability and ensures a smoother development experience in React applications.