---
title: "React Compiler Explained: Do You Still Need useMemo, useCallback, and React.memo?"
published_at: "2026-08-10T10:09:06+00:00"
modified_at: "2026-08-10T10:09:08+00:00"
url: "https://www.syncfusion.com/blogs/post/react-compiler-usememo-usecallback"
excerpt: "Learn how React Compiler changes memoization in React, when useMemo, useCallback, and React.memo still matter, and how to optimize performance effectively."
taxonomy_category:
  - "Developer Best Practices"
  - "Developer Tools"
  - "Next.js"
  - "Performance Optimization"
  - "React"
  - "React Development"
taxonomy_post_tag:
  - "React Compiler"
  - "React Performance"
  - "React.memo"
  - "useCallback"
  - "useMemo"
---

# React Compiler Explained: Do You Still Need useMemo, useCallback, and React.memo?

[Arunachalam Kandasamy Raja](https://www.syncfusion.com/blogs/author/arunachalam-kandasamy-raja)

![React Compiler Explained Do You Still Need useMemo, useCallback, and React.memo](https://www.syncfusion.com/blogs/wp-content/uploads/2026/08/React-Compiler-Explained-Do-You-Still-Need-useMemo-useCallback-and-React.memo_.jpg)


**TL;DR:** React Compiler can automatically optimize many memoization patterns that it can safely analyze, reducing the need for routine **useMemo**, ** useCallback**, and ** React.memo** usage. Learn what the compiler optimizes, where manual memoization still adds value, how performance best practices change, and how to enable React Compiler in Next.js and Vite projects.

You open a React component and see a familiar pattern:

- A couple of `useMemo` calls
- Several `useCallback` hooks
- A `React.memo` wrapper around a child component

Everything looks optimized. Yet the component is still difficult to read, nobody wants to touch the dependency arrays, and it’s not even clear whether any of those optimizations are helping.

For years, this was normal React development.

If a value was an object, we wrapped it in `useMemo`. If a function was passed to a child component, we reached for `useCallback`. If a component re-rendered too often, we added `React.memo` and hoped for the best.

React Compiler changes that workflow.

Instead of manually sprinkling memoization throughout your application, React Compiler can automatically optimize many common memoization patterns that it can safely analyze during the build process. The result is simpler components, fewer dependency arrays, and less performance-related boilerplate.

But does that mean `useMemo`, `useCallback`, and `React.memo` are officially obsolete?

Not quite.

The real answer is more practical than the headlines suggest.


## Why manual memoization became a habit

Before React Compiler, developers often optimized for reference stability rather than real performance problems.

They commonly used:

- `useMemo` to cache calculated values.
- `useCallback` to keep function references stable.
- `React.memo` to prevent child components from re-rendering when props were unchanged.

A typical component slowly turns into this:

JavaScript

```
import { useMemo, useCallback } from "react";

function ProductSearch({ products, query, onSelect }) {
  const visibleProducts = useMemo(() => {
    return products.filter((product) =>
      product.name.toLowerCase().includes(query.toLowerCase())
    );
  }, [products, query]);

  const handleSelect = useCallback(
    (id) => {
      onSelect(id);
    },
    [onSelect]
  );

  return (
    <ProductList
      products={visibleProducts}
      onSelect={handleSelect}
    />
  );
}
```

There’s nothing wrong with this approach.

The problem is that many teams adopted it by default, even when no measurable performance benefit existed.

Over time, components became harder to maintain because developers had to:

- Keep dependency arrays accurate
- Avoid stale closures
- Understand memoization behavior across the component tree
- Review optimization code that often delivered little value

The end result was frequently more complexity than performance.

## What is React Compiler?

React Compiler is a build-time optimization tool that analyzes React components and automatically applies memoization when it can safely prove that doing so won’t change behavior.

In practical terms, it allows developers to write straightforward React code while letting the compiler handle many of the optimization decisions behind the scenes.

Consider this example:

JavaScript

```
function ProductSearch({ products, query, onSelect }) {
  const visibleProducts = products.filter((product) =>
    product.name.toLowerCase().includes(query.toLowerCase())
  );

  const handleSelect = (id) => {
    onSelect(id);
  };

  return (
    <ProductList
      products={visibleProducts}
      onSelect={handleSelect}
    />
  );
}
```

Without a compiler, many developers would automatically add `useMemo` and `useCallback`.

With React Compiler enabled, that extra code is often unnecessary.

The important detail is that React Compiler only optimizes patterns it can safely analyze. If a component violates React rules or contains patterns the compiler cannot guarantee, it simply skips those optimizations.

That means the goal isn’t to stop thinking about performance. The goal is to stop optimizing everything preemptively.

## When React Compiler can make manual useMemo and useCallback unnecessary

React Compiler is particularly effective in situations where developers previously used memoization as a precaution rather than a necessity.

### Derived values

A common example is calculating filtered or transformed data from props.

JavaScript

```
function InvoiceSummary({ invoices, status }) {
  const filteredInvoices = invoices.filter(
    (invoice) => invoice.status === status
  );

  const total = filteredInvoices.reduce(
    (sum, invoice) => sum + invoice.amount,
    0
  );
  return <Summary total={total} invoices={filteredInvoices} />;
}
```

Before React Compiler, many developers would wrap **filteredInvoices** and ** total** in `useMemo`.  
 With React Compiler enabled, this kind of pure derived value may be a good candidate for automatic optimization. The compiler’s ability to optimize it depends on whether the calculation is pure and follows patterns the compiler supports. Not every derived value is guaranteed to be cached.

### Inline event handlers

Another common pattern is wrapping every event handler with `useCallback`.

JavaScript

```
function TodoItem({ todo, onToggle }) {
  const handleChange = () => {
    onToggle(todo.id);
  };

  return (
    <label>
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={handleChange}
      />
      {todo.title}
    </label>
  );
}
```

Many teams previously used `useCallback` here solely to preserve function identity.

In compiler-enabled applications, this level of manual optimization is often unnecessary.

### Lightweight object props

Developers also frequently memoized simple configuration objects.

JavaScript

```
function ChartPanel({ data, theme }) {
  const chartOptions = {
    color: theme.primaryColor,
    showLegend: true,
  };

  return <RevenueChart data={data} options={chartOptions} />;
}
```

React Compiler can often optimize these scenarios without requiring additional hooks.

## When you still need useMemo

React Compiler reduces routine memoization, but it does not eliminate legitimate performance bottlenecks.

Use `useMemo` when:

- A calculation is genuinely expensive
- Profiling shows measurable render costs
- Inputs change far less frequently than renders

Caching improves user-visible performance

JavaScript

```
function AnalyticsView({ events }) {
  const report = useMemo(() => {
    return buildLargeReport(events);
  }, [events]);

  return <ReportTable report={report} />;
}
```

Even if `buildLargeReport()` processes thousands of records and performs grouping, sorting, and aggregation, an expensive calculation does not automatically require manual memoization. React Compiler may already optimize the calculation when it can safely analyze the code. If profiling shows that the calculation is still a bottleneck, keeping `useMemo` may be appropriate.

The key difference in 2026 is intent.

- You’re no longer adding `useMemo` because a value is an array or object.
- You’re adding it because you’ve identified an actual problem.

## When you still need useCallback

The strongest use case for `useCallback` is when function identity becomes part of an integration contract.

JavaScript

```
function MapView({ map, selectedId }) {
  const handleMarkerClick = useCallback(
    (markerId) => {
      map.focusMarker(markerId);
    },
    [map]
  );

  useMapMarkerEvents(map, handleMarkerClick);

  return <MapCanvas selectedId={selectedId} />;
}
```

In this scenario, the callback is tied to an external system.

Removing `useCallback` may cause unnecessary subscriptions, listener re-registration, or unexpected behavior.

Keep `useCallback` when:

- Third-party libraries compare callback references
- Custom hooks depend on stable callbacks
- Removing it creates measurable regressions
- Reference identity is part of the API contract

## When you still need React.memo

`React.memo` remains useful for expensive components that receive stable props.

JavaScript

```
const LargeRow = React.memo(function LargeRow({ row, onOpen }) {
  return (
    <div className="row" onClick={() => onOpen(row.id)}>
      {row.title}
    </div>
  );
});
```

The mistake many teams make is wrapping everything with `React.memo`.

A component should earn memoization through profiling, not receive it by default.

Use it when:

- Rendering is expensive
- Props remain stable
- Profiling confirms benefits

Skip it when:

- Props change constantly
- Rendering is cheap
- Comparison costs exceed render costs

## **React Compiler vs Traditional Memoization**

The easiest way to think about React Compiler is this: React Compiler is your baseline optimization strategy.

Manual memoization becomes the exception, not the default.

A practical workflow now looks like this:

1. Write clear, predictable React code.
2. Enable React Compiler.
3. Measure real performance bottlenecks.
4. Add `useMemo`, `useCallback`, or `React.memo` only where evidence supports it.

That approach generally produces code that is easier to read, maintain, and optimize over time.

## React Compiler setup

React Compiler runs through your build tool.

### Next.js

First, install the compiler package:

```
npm install -D babel-plugin-react-compiler
```

Then enable React Compiler in `next.config.js`:

next.config.js

```
// next.config.js
const nextConfig = {
  reactCompiler: true,
};
export default nextConfig;
```

### Vite

For Vite, React Compiler setup requires installation because the compiler runs through Babel integration.

Install the required dev dependencies:

```
npm install -D babel-plugin-react-compiler @rolldown/plugin-babel
```

Then configure React Compiler in your Vite setup according to the React documentation and the version of `@vitejs/plugin-react` used in your project.

The exact configuration can vary between releases, so always verify against the latest React documentation before enabling it in production.

## Frequently Asked Questions

How do I know if React Compiler skipped a component?React Compiler only optimizes code it can safely analyze. Components that violate React rules, contain mutations, or depend on unsupported patterns may be skipped. React’s ESLint rules are the easiest way to identify potential issues before they become performance problems.

Can I use React Compiler with React 18?Yes. Although React Compiler is designed to work best with React 19, it supports React 17 and React 18 through additional runtime and compiler configuration. Always review the latest React documentation for current compatibility and setup requirements before enabling it in production.

Will React Compiler fix slow API calls?No. React Compiler optimizes rendering work. It won’t reduce network latency, speed up database queries, or improve oversized API responses.

If your application is slow because data arrives slowly, performance work should focus on caching, pagination, streaming, and backend architecture instead.

Should I Still Profile React Applications?Absolutely. React Compiler improves the baseline, but profiling remains the only reliable way to identify real bottlenecks.

Use React DevTools Profiler to understand render behavior and browser performance tools to investigate scripting, layout, paint, and interaction delays.


## Conclusion

React Compiler changes one of the longest-running habits in React development.

For years, many developers reached for `useMemo`, `useCallback`, and `React.memo` before they knew whether performance was actually a problem. Today, React Compiler can automatically handle many of those routine optimizations when it can safely analyze the relevant code.

That doesn’t make manual memoization obsolete. It simply changes when you should use it.

The new default is straightforward:

1. Write readable React code.
2. Let the compiler optimize safe cases.
3. Measure performance.
4. Add manual memoization only when the data proves it’s necessary.

In 2026, `useMemo`, `useCallback`, and `React.memo` are still valuable tools. They’re just no longer the first tools you reach for.

## Related Blogs



[Less Custom Code, Smarter Scheduling: What’s New in Pure React Scheduler 2026 Volume 2](https://www.syncfusion.com/blogs/post/pure-react-scheduler-2026-volume-2)



[Redux vs Zustand: Choosing the Right React State Manager](https://www.syncfusion.com/blogs/post/redux-vs-zustand-react-state-management)



[React 19 Suspense for Data Fetching: A New Model for Async UI](https://www.syncfusion.com/blogs/post/react-19-suspense-for-data-fetching)



[Building a Modern Query Builder with React 19 Server Components](https://www.syncfusion.com/blogs/post/build-query-builder-in-react-19)
