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.

useEffectuseMemoso sánhkhác biệthook Reactside effect
Cover image: useEffect vs useMemo: 5 Key Differences You Need to Understand
Avatar of Trung Vũ Hoàng

Trung Vũ Hoàng

Author

28/3/20264 min read

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.

Found this article helpful?

Contact us for a free consultation about our services

Contact us

Bài viết liên quan