useEffect vs useMemo: 5 Key Differences You Need to Understand
Confusing useEffect and useMemo is one of the most common sources of performance issues in React apps. Think of useMemo as a calculator that remembers results, and useEffect as a switchboard operator waiting for external signals before acting.

Trung Vũ Hoàng
Author
1. The Core Purpose of Each Hook
useMemo exists to solve memoization - caching the result of an expensive computation and only recomputing when its dependencies actually change. Its sole goal is to prevent heavy calculations from rerunning unnecessarily after every component re-render.
useEffect is the opposite - it handles side effects: tasks outside a component's render scope such as calling an API, setting up subscriptions, or directly interacting with the DOM. If you put computation logic in useEffect, React has to render again to update state, which is wasteful.
2. Execution Timing: A Critical Difference
useMemo runs during the render phase. When React reads the component code to prepare the UI, it checks the dependency array for useMemo - if nothing changed, the cached value is returned immediately. Therefore, never put side effects inside useMemo, as that would slow down rendering.
useEffect runs only after rendering completes and the browser has painted the UI (commit phase). This design ensures heavy tasks like data fetching do not block the user from seeing the interface - it's intentional to keep the app responsive.
3. When Should You Use useMemo?
Only use useMemo in two clear situations:
Expensive computations: Filtering lists with thousands of items, running complex search algorithms, processing large datasets, etc.
Ensure referential stability: When you return an object or array and pass it to a child component wrapped with
React.memo. Without useMemo, a new object is created on every render, so the child sees "new data" and re-renders unnecessarily.
Do not use useMemo for trivial calculations - the overhead of initializing the hook and comparing dependencies can outweigh the benefit.
4. Practical Uses of useEffect
useEffect is the control center for everything that happens outside the component. Common cases include:
Calling an API when the component mounts or when dependencies change.
Subscribing to a WebSocket to receive real-time data.
Setting up and cleaning up event listeners.
One thing useMemo does not have: a cleanup function. When a component unmounts or before the effect runs again, cleanup lets you cancel in-flight API requests, remove listeners, and free memory to avoid leaks.
Tip: Before using useEffect to update state, ask yourself: "Can I compute this value directly during render?" If yes, use useMemo or compute it inline. No useEffect needed.
5. Summary: 5 Key Differences
Difference 1: Purpose
useMemo: Cache a value ("remember something").useEffect: Handle side effects ("do something").
Difference 2: When it runs
useMemo: During render (before paint).useEffect: After render completes (after paint).
Difference 3: Return value
useMemo: A concrete value (number, string, array, object, etc.).useEffect: undefined or a cleanup function.
Difference 4: Cleanup support
useMemo: None.useEffect: Has a cleanup function on unmount or when dependencies change.
Difference 5: Impact on rendering
useMemo: Avoids extra re-renders by preserving the same value.useEffect: Can trigger additional renders if it updates state inside.
6. Common Mistakes to Avoid
Stale closures: Using variables inside a hook but forgetting to list them in the dependency array. The code reads stale data with no warning - one of the most insidious bugs.
Handling events inside useEffect: When a user clicks "Buy", handle the logic directly in onClick - don't change some intermediate state and wait for useEffect to "catch" it. The direct approach is clearer and easier to debug.
One useEffect doing too much: Follow the Single Responsibility principle - each useEffect should handle one task. This helps React manage re-renders accurately and makes the code easier for teammates to read.
Conclusion
The best thing you can do is keep components as simple as possible. Make it work first, then measure with a profiler to decide whether memoization is necessary. Don't optimize prematurely based on intuition.
Bài viết liên quan

Closures in JavaScript: Understand Them Thoroughly to Code Like a Pro
Closures—also known as "closed functions"—are one of the most powerful yet confusing concepts in JavaScript. Mastering closures not only helps you ace Senior-level interviews, but also changes how you architect your entire codebase: cleaner, safer, and less buggy. Many people confuse Scope and Closure, but they’re closely related and complementary. Let’s start from the foundations.

useEffect vs useMemo: 5 Key Differences You Need to Understand
Confusing useEffect and useMemo is one of the most common sources of performance issues in React apps. Think of useMemo as a calculator that remembers results, and useEffect as a switchboard operator waiting for external signals before acting.

useMemo vs useCallback: 3 React Optimization Tactics Senior Developers Use
Performance optimization in React is often seen as a minefield—where many developers get stuck making the wrong calls. Sprinkling useMemo and useCallback everywhere in hopes of speeding things up can backfire, forcing the CPU to do extra dependency comparisons for no reason. This article shows you how to use these two hooks like a pro.