How to Debug useMemo Hook in React

The useMemo hook is essential for optimizing performance in React, but debugging it can be challenging when values do not update as expected or recalculate too frequently. This article explains how to debug useMemo by inspecting dependency arrays, utilizing React DevTools, leveraging temporary logging techniques, and implementing ESLint rules to ensure your memoized values work efficiently.

1. Insert Inline Logging

The simplest way to check if a useMemo function is executing on every render is to insert a temporary console.log statement inside the memoization callback.

const memoizedValue = useMemo(() => {
  console.log("useMemo recalculated!");
  return computeExpensiveValue(a, b);
}, [a, b]);

If you see “useMemo recalculated!” in your console on every render, it means your dependency array is changing constantly, defeating the purpose of memoization.

2. Identify Unstable Dependencies

If useMemo is running more often than expected, it is usually because one of the items in the dependency array has an unstable reference. Objects, arrays, and functions created during render get new memory addresses on every render, which triggers useMemo to recalculate.

To debug this, you can compare the current dependencies with the previous ones using a custom hook or temporary reference logging:

const prevDeps = useRef([a, b]);

useEffect(() => {
  if (prevDeps.current[0] !== a) console.log("Dependency 'a' changed");
  if (prevDeps.current[1] !== b) console.log("Dependency 'b' changed");
  prevDeps.current = [a, b];
});

3. Use React DevTools Profiler

The React Developer Tools extension provides a Profiler tab that helps track component renders. 1. Open React DevTools in your browser. 2. Go to the Profiler tab and start recording. 3. Interact with your application to trigger updates. 4. Stop recording and select the component containing your useMemo. 5. Check the “Why did this render?” section to see if the props or state driving your useMemo are changing unexpectedly.

4. Enable ESLint Rules

Many useMemo bugs stem from forgetting to include a dependency in the array, leading to stale closures. You can prevent this by enabling the eslint-plugin-react-hooks package in your project.

Ensure your .eslintrc configuration includes:

{
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn"
  }
}

This configuration will highlight missing dependencies directly in your code editor, preventing bugs before you run the code.