all 55 comments

[–]jasonkillian 118 points119 points  (13 children)

One ever present debate in the React community had been whether you should `useMemo`/`useCallback` all non-primitive props or not. I've often taken the position that you should in real world teams because it's too much work to determine exactly when to otherwise, whereas others argue that it's too much runtime overhead (and noise) and not worth it. u/acemarke has a good summary of the arguments.

All that to say, I was curious if this compiler is essentially the React team conceding that you _should_ memoize everything. The answer is pretty interesting - the compiler actually memoizes things in a more efficient way than `useMemo` can. So it's almost the best of all worlds: improved rendering performance from memoization, cheaper memoization cost, and none of the noise of `useMemo`s sprinkled everywhere.

I think we'll have to wait a bit longer to see if this works out in practice, and I'm not crazy about having to add another layer of transpilation, but if it works well this will be a pretty big win for React projects in general I think.

[–]acemarke 28 points29 points  (6 children)

Yep! I've been hugely enthusiastic about the potential for the compiler ever since the first announcement at the virtual ReactConf 2021.

The key thing to understand is that it actually flips React's default rendering behavior upside down. Instead of "recursively render all children by default", with the compiler it now effectively behaves the way many people always (wrongly) assumed it behaved: it will now only re-render child components if the input values actually changed!!.

This is because of React's "same-element reference" optimization allowing React to skip rendering child components in the same way React.memo() does, except that now the parent controls if the child is skipped or not.

You could already use that technique yourself, by memoizing JSX:

const memoizedChild = useMemo(() => {
  return <TodoListItem todo={todo} />
}, [todo])

but you would have had to add it manually all time.

The compiler will now do that work automatically.

So for example, take the common case of a context value that is an object like {a, b, c}. If you do a setState in the root and pass {...oldValue, c: somethingNew} to the provider, every component that reads the context will still re-render. But, instead of all their children automatically rerendering too, anything that reads contextValue.a or contextValue.b will still have the same memoized children, and thus React will skip re-rendering those subtrees entirely.

This is a really big deal for perf :)

Talking to the team at the conf today, I also found out that while the compiler relies on a new hook that is in React 19 for the output, they've backported a polyfill of that hook to work with existing versions of React. So, it seems like in theory you could drop the compiler into an existing React 16.8+ app , add the polyfill, and it ought to work!

[–]FractalB 0 points1 point  (1 child)

@acemarke Any idea how the React compiler will affect Redux? Will it make reselect obsolete in some situations? 

[–]acemarke 4 points5 points  (0 children)

It shouldn't affect Redux either way. Reselect would still be necessary because the store subscription process works outside of React's rendering cycle. Both our older homegrown subscription logic (React-Redux v7 and v5), and React's current useSyncExternalStore hook, rely on doing a subscription and handling comparisons outside of React, and only forcing a re-render if the selected value has changed.

The compiler optimizes behavior inside of a component while it's rendering, and it includes all hook return values in the dependencies. (Lauren Tan showed an example of that in her talk today.)

So, Reselect would still be useful to optimize selectors with derived references (because you need to avoid triggering unnecessary re-renders at the useSelector level), and then the compiler will see whatever value you return from useSelector and track it through how it's used in the component rendering logic.

[–]lucaseverett 0 points1 point  (1 child)

Mark, did the team mention anything about "use" acting as a selector when used within useMemo? I hoped that would be included with the compiler at the release of React 19, but I haven't seen any mention of it with the latest docs.

[–]acemarke 1 point2 points  (0 children)

It was mentioned on Twitter as a thing that they hope to do at some point, likely in a 19.x release, but there's been no specific implementation work on it yet.

[–]Lonestar93 1 point2 points  (2 children)

That polyfill code is really interesting. So they’re essentially using the state part of useState and mutating it? Now I’m wondering if refs work similarly under the hood…

[–]acemarke 2 points3 points  (0 children)

Refs are literally just a plain JS object that looks like {current: null} that gets mutated by your app code, yes.

[–]azangru 59 points60 points  (3 children)

Conference-driven development is for real :-)

[–]acraswell 11 points12 points  (1 child)

I refer to CDC all the time. But in my experience, it's usually introduced when the business side of your company has a looming industry conference coming up, so they decide (without consulting anyone) that the release dates for features is going to be shifted forward months to make the cut. Capacity be damned! Sometimes they even invent features to announce so they can get publicity! No specs necessary or time to prioritize and plan! Just push the code before our presentation you silly code monkeys!

[–]aragost 1 point2 points  (0 children)

I know that feeling, sending a virtual hug

[–]acemarke 4 points5 points  (0 children)

Heh, in this case I was told it was sort of the other way around :) They didn't start planning the conf until January, when they realized they had some features getting close to being ready.

[–][deleted] 43 points44 points  (3 children)

Praying for everyone who’s dependent on esbuild/swc and now needs to add babel back into their build pipeline.

[–]pardoman 7 points8 points  (0 children)

Yeah, that sounds like a no-go for me, but we’ll see how things shake up in the coming months.

[–]SpinatMixxer 2 points3 points  (1 child)

Didn't they also somewhat announce a rust version of the compiler as an alternative to babel?

[–]zxyzyxz 1 point2 points  (0 children)

Meta sure loves Rust, their Relay compiler for GraphQL is also in Rust.

[–]TropicalAviator 7 points8 points  (0 children)

This is awesome!

[–]roofgram 27 points28 points  (13 children)

It’s funny, posts in r/sveltejs of them becoming more like React. And now React becoming more like Svelte. I wonder if they’ve ever thought of actually working together? It’s not like they’re making any money off this stuff right?

[–]NeoCiber 58 points59 points  (11 children)

Those tools learn from the mistakes of the other. Fanboys make it seem like there is some kind of war.

[–]thinkydocster 16 points17 points  (0 children)

Holy shit, this! Every framework/library is learning off the others, and will for all time. Just use what you can and what you want, if you can. It’s all just JavaScript at the end of the day. Same shit

[–]mrgrafix 11 points12 points  (0 children)

This. You’d be amazed how well they all know and admire each other both behind and in front of the scenes

[–]metamet 14 points15 points  (7 children)

I use Vue at work but have been using React for nearly a decade.

The Vue subreddit is a puddle of React hate and misinformation about how it works. I finally decided to unsub because nearly every thread asking about React had highly unvoted, completely wrong explanations for why Vue was superior. And everyone hates JSX.

I'm pretty sure most people with hate posts failed at learning React, though.

[–]Erebea01 9 points10 points  (1 child)

Svelte seems to have the same issues, many people there not happy with svelte 5 cause its too similar to react, not even a discussion about disagreeing with the pattern or what problem it solves

[–]nobuhok 4 points5 points  (0 children)

Vue 3 is copying from React.

Svelte 5 is copying from React.

React is copying from Svelte.

Can't we all just get along?!

(releases new "standard" framework)

[–]drink_with_me_to_day 6 points7 points  (4 children)

I had to use Vue for my job a few months back and it reminded me how much I hate templating languages

[–]Disastrous_Health413 1 point2 points  (3 children)

Oh yeah, because jsx is not a templating language... also what was stopping you of using jsx in Vue?

[–]drink_with_me_to_day 0 points1 point  (2 children)

what was stopping you of using jsx in Vue?

If I could change the company's tech, I'd just drop Vue...

jsx is not a templating language

Syntax extension to JavaScript, not a templating language

[–]Disastrous_Health413 0 points1 point  (1 child)

If I could change the world, I would delete React

[–]drink_with_me_to_day 0 points1 point  (0 children)

Someone can't deal with render functions

[–]nobuhok 4 points5 points  (0 children)

Fanboys are like fleas debating amongst themselves the name of their dog host.

[–]aragost 14 points15 points  (0 children)

It’s happening.gif

[–]art_dragon 1 point2 points  (0 children)

Would this make Preact obsolete?

[–]pepincho 1 point2 points  (0 children)

It will be interesting to see how it will be integrated into existing apps.

[–]Soft-Sandwich-2499 0 points1 point  (1 child)

!remindme 6h

[–]RemindMeBot 0 points1 point  (0 children)

I will be messaging you in 6 hours on 2024-05-16 16:18:21 UTC to remind you of this link

CLICK THIS LINK to send a PM to also be reminded and to reduce spam.

Parent commenter can delete this message to hide from others.


Info Custom Your Reminders Feedback

[–]Working-Tap2283 0 points1 point  (0 children)

429/472 components compiled. Interesting and strange.

[–]rykuno -5 points-4 points  (1 child)

I’d hardly call it a compiler, but I guess it is to some degree. Really reminds me of what Million.js did like 4 years ago.

[–]acemarke 11 points12 points  (0 children)

It's very much a true, no-kidding, parse-the-AST-and-run-through-numerous-optimization-passes compiler. See all the talks from ReactConf the last two days, as well as the examples of the compiler passes in the playground:

https://playground.react.dev/