React Compiler & React 19 - forget about memoization soon?
Tags: react, webdev, javascript, performance
Published: 2024-03-13 17:09:53


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/42c96ayhzw77v7620qzt.png)

React 19 and the React Compiler, previously known as React Forget, have been dominating the React discussion over the past month. We're all losing our minds (in a good way) over the possibility of never having to think about memoization in React very, very soon. Is it true, though? Should we start forgetting about `memo`, `useMemo`, and `useCallback` in the coming months? And what actually changes when the React Compiler is released, and what should we learn and teach about React after that?

Let's take a look.

## React 19 is NOT the React Compiler


Let's get the most important thing out of the way: memoization is not going anywhere soon, so don't unlearn it just yet. React 19 is not the React Compiler. The React team announced the Compiler in [the same blog post](https://react.dev/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024) where they announced the soon release of React 19, and everyone excitedly jumped to conclusions.

A tweet from a React team member, however, clarifies this confusion:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ds8vnolkzvhw5hh7k0vn.png)

In React 19, we'll see a bunch of new features, but we'll have to wait a bit longer for the Compiler. It's not clear right now how long, but according to another tweet from a different React core team member, it might happen by the end of this year.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ax1i1bai1eyiwdme4dm.png)

Personally, I'm skeptical of this timeline. If we look at the talk by [the React team members](https://www.youtube.com/watch?v=qOQClO3g8-Y) that introduced the Compiler and its timeline, we're in the middle of the Compiler's journey:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4n7sn1ijjs5ro3vjyiv5.png)


The journed started in 2021, [two years ago](https://www.youtube.com/watch?v=lGEMwh32soc). Rolling out something as fundamental as this on a codebase as large as Meta is probably very complicated. So the jump from the middle of the timeline to the end might take another 2 years.

But who knows, maybe the React team will actually manage to release it this year. That would be good news. The current promise of the Compiler, [mentioned in the video](https://www.youtube.com/watch?v=qOQClO3g8-Y), is that we won't need to change any code for its adoption. It will Just Work ™️. If it's actually released by the end of the year, it's a very good indication that this is indeed the case, and the rest of us should be able to switch to it quickly and easily.

However, even if the Compiler is released this year, and it is indeed very easy to adopt with no downsides, it doesn't mean that we'll be able to forget about `useCallback` and `memo` right away. There will always be a "transition" period, where we first talk about the case of "if you already have the Compiler enabled", that slowly transitions to "in the rare case you haven't migrated to the Compiler yet" scenario.

The mental transition from class components to functional components with hooks took, I think, at least 3 years (starting from 2018) - when all the courses, docs, and blogs caught up, most people migrated to the React version with hooks, and we started talking about functional components and hooks as a default. And even today, 6 years later, there are still plenty of class components lurking around here and there.

If we apply a similar timeline to the Compiler, that would mean that we'd need to hold onto the knowledge of what `memo`, `useMemo` and `useCallback` are for at least the next three years. Less, if you're lucky enough to work in a modern codebase that can migrate to the Compiler as soon as it's released. More, if you're a React teacher or work in a large codebase that is slower to migrate with plenty of legacy code.

## What changes with the React Compiler


So what exactly is changing? The simplified answer is - everything will now be memoized. The React Compiler will be a Babel plugin that converts our typical React code into code where every hook dependency, props on components, and components themselves are memoized. Essentially, this code:

```tsx
const Component = () => {
  const onSubmit = () => {};
  const onMount = () => {};

  useEffect(() => {
    onMount();
  }, [onMount]);

  return <Form onSubmit={onSubmit} />;
};
```

underneath will behave as if both `onSubmit` and `onMount` are wrapped in `useCallback` and `Form` is wrapped in `React.memo`:

```tsx
const FormMemo = React.memo(Form);

const Component = () => {
  const onSubmit = useCallback(() => {}, []);
  const onMount = useCallback(() => {}, []);

  useEffect(() => {
    onMount();
  }, [onMount]);

  return <FormMemo onSubmit={onSubmit} />;
};
```

The Compiler doesn't convert them into _exactly_ that code, of course, it's much more complicated and advanced than this. But it's a good mental model to wrap our heads around it. If you're curious about the exact details, I recommend [watching this video](https://www.youtube.com/watch?v=qOQClO3g8-Y) from the React core team members who introduced the Compiler. And if you're slightly fuzzy on why we'd use `useCallback` and `memo` here at all, I'd recommend watching the first six videos of [the Advanced React series](https://www.youtube.com/playlist?list=PL6dw1BPCcLC4n-4o-t1kQZH0NJeZtpmGp) on YouTube. They cover everything about re-renders and memoization. Alternatively, if you're more into reading, then read [everything here](https://www.developerway.com/tags/re-renders).

For the way we're teaching and learning React, this transition means a few things.

### If parent re-renders, child re-renders

Currently, if a Parent component re-renders, every component rendered inside will re-render as well.

```tsx
// if Parent re-renders
const Parent = () => {
  // Child will also re-render
  return <Child />;
};
```

A lot of people currently believe that the `Child` component re-renders only if its props change. I like to call this [The Big Re-renders myth](https://www.developerway.com/posts/react-re-renders-guide#part2.5). At the moment, this is not true. Props don't matter in the standard React behavior.

Funnily enough, it becomes true with the Compiler. Since everything is memoized under the hood, the current myth actually becomes the standard React behavior. In a few years, we're going to teach that a React component re-renders only if its state or props change, and whether the Parent re-rendered or not doesn't matter. Life is weird sometimes.

### No more composition for performance

Currently, we have a few composition techniques like ["moving state down"](https://www.developerway.com/posts/react-re-renders-guide#part3.2) or ["passing components as children"](https://www.developerway.com/posts/react-re-renders-guide#part3.3) that can reduce re-renders. I usually recommend using them before messing around with `useCallback` and `memo`, since [memoizing things in React properly is very, very hard](https://youtu.be/huBxeruVnAM?si=xr2_IB8PErDgFYse).

For example, in this code:

```tsx
const Component = () => {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Button onClick={() => setIsOpen(true)}>
        open dialog
      </Button>
      {isOpen && <ModalDialog />}
      <VerySlowComponent />
    </>
  );
};
```

the `VerySlowComponent` re-renders every time the dialog opens, causing the dialog to open with a delay. If we encapsulate the state that opens the dialog in a component like this:

```tsx
const ButtonWithDialog = () => {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Button onClick={() => setIsOpen(true)}>
        open dialog
      </Button>
      {isOpen && <ModalDialog />}
    </>
  );
};

const Component = () => {
  return (
    <>
      <ButtonWithDialog />
      <VerySlowComponent />
    </>
  );
};
```

we essentially got rid of the unnecessary re-renders of the `VerySlowComponent` without memoizing anything.

When the compiler comes to life, these patterns will become unnecessary for performance. We'll probably still use them for composition and separation of concerns purposes. But there won't be a natural re-renders power anymore that forces us to split components into smaller components. Our components might become larger with no negative consequences.

### No more useMemo/useCallback everywhere

Naturally, all the `useMemo` and `useCallback` that sometimes plague our code will be gone. That part excites me the most. No more tracking props through multiple levels of components just to memoize one `onSubmit` props callback. No more unreadable and undebuggable chains of `useMemo` and `useCallback` that all depend on each other and are impossible to understand. No more broken memoization just because `children` are not memoized and no one noticed.

### Diffing & reconciliation

We might need to change how we explain [diffing & reconciliation in React](https://www.developerway.com/posts/reconciliation-in-react). The current simplified explanation is that when we "render" a component like this `<Child />`, we just create an Element of it. This element is an object of that shape:

```json
{
  "type": ...,
  "props": ...,
  // other react stuff
}
```

where "type" is either a string or a reference to a Component.

In this code:

```tsx
const Parent = () => {
  return <Child />;
};
```

when `Parent` re-renders, its function is triggered, and `<Child />` object is re-created. React performs a shallow comparison of that object before and after re-render, and if its reference changes, then it's an indication for React that it needs to do a full diffing on that sub-tree.

Currently, this is the reason why the `<Child />` component always re-renders, even if it doesn't have any props. The result of `<Child />` (which is a syntax sugar for `React.createElement` function call) is an object that is always re-created, which means it can't pass the shallow comparison check.

With the React Compiler, the concepts of Elements, diffing, and reconciliation remain the same, so that's good. But it seems that `<Child />` will now return a _memoized object_ if its props haven't changed. So, actually, the end result of the Compiler is more of an equivalent of everything being wrapped in `useMemo`, even the Elements.

```tsx
const Parent = () => {
  const child = useMemo(() => <Child />, []);
  return child;
};
```

But this is just me making assumptions from the limited publicly available resources, so I might be slightly wrong here. In any case, it's just an implementation detail that doesn't really matter for our production code.

---

Everything else stays pretty much the same as it is right now. Creating components inside other components will still be [a massive anti-pattern](https://www.developerway.com/posts/reconciliation-in-react#part10). We'll still use [the "key" attribute](https://youtu.be/cyAbjx0mfKM?si=cUVQb_aXGHsirMvZ) to identify elements or reset the state. [Context](https://www.developerway.com/posts/how-to-write-performant-react-apps-with-context) is still going to be a pain to deal with. And everything about data fetching or error handling is not even part of the conversation.

But anyway, I can't wait for the Compiler's release. It seems like a massive improvement to our React life. Even if I have to re-write half of my articles and re-do half of my YouTube videos because of it 😅

---

Originally published at [https://www.developerway.com](https://www.developerway.com). The website has more articles like this 😉

Take a look at the [Advanced React book](https://advanced-react.com/) to take your React knowledge to the next level.

[Subscribe to the newsletter](https://www.developerway.com), [connect on LinkedIn](https://www.linkedin.com/in/adevnadia/) or [follow on Twitter](https://twitter.com/adevnadia) to get notified as soon as the next article comes out.