Hacker News new | past | comments | ask | show | jobs | submit login
Understanding React Compiler (tonyalicea.dev)
114 points by kiyanwang 3 months ago | hide | past | favorite | 204 comments



I used to think that React is awesome, but this has gone too far. They just don't care about JavaScript.

1. They introduced hooks which must be called in the same order for every execution. You can't put hook inside `if`. Hooks are based on magic. This is terrible design.

2. They didn't adopt async/await, inventing their own suspend stuff.

3. Now this: they just convert the source language into something else.

The JSX idea is gold: introduce XML-like template syntax into the language to avoid need for foreign template language. Make XML templates valid at startup and even with proper types for TypeScript. This is very important advancement compared to text templates which are used everywhere else.

The stateless render function is good. Emit desired-state, let framework to reconcile current state to desired state.

But rest of React is not gold.


Hooks are not magic, they just increment an index that's used to access the state, which is saved in an array. So you have to call the same hooks at the same time on each component function call. That's it, zero magic.

Async and await is not useful for React, Suspense is done out of necessity. It's have to be generators if anything - but Suspense is older than wide support of generators and async/await too.

You don't have to use hooks nor Suspense at all - just use your own state management and pass it as a prop at the root render call, or no state at all.


> Hooks are not magic, they just increment an index

I think it’s reasonable to wonder why they’re implemented in such a strange and brittle manner as that. Vue needs no such weirdness, the composition api just uses normal scoping in JS.


I'm not sure why you're being downvoted.

Your comment might not bring much new information, but I agree with what you say.

Except maybe for one thing: "state" is about observability. That's what justifies the "rules of hooks", not the inplementation details.

I guess people call hooks magic because they look simpler than they are, as if their implementation would rely primarily on closures, which is not the case.

But they play very well with reasoning about closure scoped inside of React components.

Regarding async/await, I'm really pretty much torn. Why can't Suspense wait for any Promise to resolve? Or has this changed by now?

Regarding conditional hook calls: this is really a non-issue in practise, it sometimes even helps with code quality.

Would you initialize an observable property of an object/component conditionally?

I think I'd prefer to avoid that as well.


Conceptually, a `<Suspense>` component acts like a `try` boundary around a given component subtree. If _any_ component inside of that subtree suspends, it needs to "bubble up" to the ancestor `<Suspense>`.

But, React implements the core component tree rendering logic via a single `while` loop that iterates downwards. That's flat, logic-wise, whereas the tree is nested.

Meanwhile, React already had similar behavior for its error boundaries, where a thrown error in a component would get caught by the component rendering logic and it would "bubble up" to the nearest error boundary.

So, they opted to implement Suspense's mechanics the same way, except that instead of throwing an error, you throw a `Promise`.

Meanwhile, React components on the client have always been pure synchronous functions. No `async/await`, no generators, and thus no support for returning a promise from a function.

With React Server Components, React now supports `async function` components _on the server only_. They've done some prototyping with support async components on the client (and I think even briefly accidentally had a couple releases where that technically was turned on), but there's some kind of either technical issue or release planning issue that's kept them from building out that support for client components (possibly support for `AsyncContext` in browsers).


Thanks for your explanation.

What I don't understand is why there's no easy way to conditionally render a subtree depending on promises contained in the props of the top-level component.

Kind of like a guardian HOC triggering a re-render whenever all props promises resolve.

Is it because that would be a one-time thing and not synchronously reactive?

Seems like people reimplement or reuse this kind of thing all the time, but often using useEffect (transforming side-effects into state, losing deterministic rendering).

You're right that this would get ugly really fast with nested suspense boundaries though.


Hmm. Trying to understand what you're suggesting here.

You can pass _any_ JS value as a prop to a child component, and there's nothing special about any of that as far as React is concerned. You can pass a primitive, an object, a Promise, an AbortController, a DOM node, anything. All React cares about is "here's what gets passed into the child".

Suspense has a couple key bits of behavior: it needs to let _deeply_ nested components trigger the _nearest_ Suspense boundary, and it also needs a way for React to know when the async behavior is done (ie, the promise resolves) so that it knows when to re-render. Throwing a promise is certainly unusual conceptually, but makes sense in light of those constraints.

(I'm probably misunderstanding what you're envisioning and didn't manage to answer it properly - feel free to clarify with an example if you'd like!)


Yes I'm not sure myself if what I say makes sense when thinking it through again.

I was thinking something like

  <WithPromises asyncProp={promise} asyncProp2={promise2}>
    {(resolvedValues) => children(resolvedValues)}
  </WithPromises>

But that's already possible to do yourself I guess, but better in different way.

E.g. not using a function prop as "children" etc.

Many libraries also provide nice and clean interfaces to provide async state (e.g. react-query) and then of course there's good old useEffect.

I think I see why they use a different approach.

Guess I'd mainly just love a streamlined API for data fetching built into the core.

Right now it's a lot better to just have async code outside of react change prop values.

Love the section on client data fetching in the react docs though.


Generators were in every browser in early 2017 and Suspense was in late 2017?


Latest version of every browser, not every browser version I was forced to support because it was still used by a big chunk of users...


When it comes to composition, hooks are a godsend. I don't understand how so many dislike them, they were what made me finally go "wow, react is better than backbone / marionette". Well, that and being able to do <></>. Although to be fair marionette struggled with that sort of thing too (replaceElement anyone?).

Once you learn the basics, as long as you stick to them you can write code so fast / solid.

I haven't bothered with anything beyond hooks, so maybe that's why I'm content.


Exactly. React made composing components natural. Hooks made composing state and logic natural. For all its faults React deserves a lot more credit for this. Really the ideas behind hooks need a new language to make them shine and this compiler is a step in that direction.


I explored using TSX in a non-React way and have been quite proud of my results [0]. I mostly understand hooks and I get why they went that direction, but I swapped hooks for RxJS Observables in my library. I know for some developers they are just as hard to "understand" as hooks, but no one has ever accused Observables of being "magic", at least. Observables end up looking like hooks in basic component examples, but then you can pull them out and reason with them very easily in "view models". In some ways my library feels more like the early days of React when React was just a library, but with some modern benefits.

[0] https://worldmaker.net/butterfloat/


That's a great library! Looking forward to use it in some personal project.

In a React-based project, I managed to use RxJS through react-rxjs[0] to manage events and state. Thanks to it, I was able to fully streamline state management in that project.

[0] https://react-rxjs.org/


This sounds very similar to the development of my project. Basically every word of that could apply to https://mutraction.dev/


Observables aren't magic. They're just shit.


I used to really think hooks were crazy, but now I see them as a reasonable way to write a “DSL”. They are very nice from the viewpoint of reuse and software composition. I have even implemented things in Python that work like hooks.

React does let you do a lot in async, when you are managing the rendering of components something like Suspense could be the right idea but I have a very big application that breaks some of the rules of React but gets away with it and I don’t know how it will do in React 18.


> The JSX idea is gold: introduce XML-like template syntax into the language to avoid need for foreign template language. Make XML templates valid at startup and even with proper types for TypeScript. This is very important advancement compared to text templates which are used everywhere else.

It’s really nice. It started in php as xhp in the late 2000s and was later ported to JavaScript as jsx.


I'm currently building a framework that's essentially "imperative JSX". It sounds like a step backwards but I built a todo app last night with it and I really like the model I came up with. It resolves virtually all of the weird issues with state management in React, because state management is now orthogonal to the render tree.


React Server Components are async/await. Suspense works with async/await to show loading indicators (it is not a replacement as you are implying). They said they have plans to bring async await to Client Components but they need the AsyncContext tc39 proposal to come to JS first.

The worst part of react is all the FUD hacker news creates about it every time they try to innovate to make the web's defacto framework better.


Async/await and suspend are not at all comparable.


If anyone likes the idea of JSX but with python, checkout

https://pixyverse.dev


Hooks solve the problem of composing lifecycle effects. How would you do it without a hook-like pattern?


Is Preact a fine alternative if all you’re after is JSX and declarative UI?


Preact is an excellent alternative to React that keeps things minimal, understandable, and fast.


You must be ready to build a lot yourself. As nontrivial as can be.


One radical lightweight alternative to React is Svelte

https://svelte.dev/

which is completely dependent on a compiler since it bakes in all of the updating logic at that stage. I haven't done big projects with it but for little projects I have been amazed at the speed and the small size of the bundles.


> They just don't care about JavaScript.

Good. JavaScript sucks.


I love React. It feels foundational somehow. It's also vindicating after toiling for years on bloated frameworks. Declaratively describe your UI, React paints it. That's it. No app state management. No routing. No learning yet another templating system (which inevitably morphs into a shitty programming language). Just full JS(X optional). No grokking convoluted, bespoke abstractions. It's clean, narrowly scoped, and as simple as possible (but not simpler).

Having recently worked on two legacy apps -- one ASP.NET, one Angular -- it made me deeply appreciate React and how far UI tech has come. Phenomenal work from the React team on more optimizations via this compiler. Good article too.


> Declaratively describe your UI, React paints it. That's it. No app state management.

"that's it" does not paint the full picture. Yes, UI = function(state) is very convenient but the way React implements it inverts the problem. Now instead of having to figure out ways of updating everything you have to go through numerous hoops to get only the things you need to update.


> Now instead of having to figure out ways of updating everything you have to go through numerous hoops to get only the things you need to update.

That's literally the point of React Compiler


No, you don't. React does.


I think I get what GP means. Without very judicious use of useMemo, you can't move a piece of state into an outer component without causing the rest of its children to also be re-rendered when the state is changed. I recall having to fiddle around with useRef at least a few times due to this, to avoid lots and lots of useMemo churn.


But that's the whole point of react compiler, which is the whole point of the post we're talking under


Have you tried wrapping component exports with memo? That basically solved everything for me. It’s the equivalent of functional components from before hooks.

> export default memo(ExampleComponent)


Same would be true for:

- Preact (like react, but tiny)

- Solid (like react, but tiny and without the stupid re-rendering, or the stupid rules of hooks)

- Lit (like react; but tiny, based on the browser-native web components, and with a class-based api)

Considering that React has a virtual dom, a separate templating language (jsx), and now also a compiler, I would not call it simple.


God I love Lit. I wish more outfits were running it, templating in ‘lit-html’ is such a good experience.


This is not my experience at all. I write some visualization. I want to add a UI to tweak the numbers. I add React. React requires me to re-write all of my state for its `setState` stuff.


State management is the worst part of React IMO. Basic things with `useState` aren't too bad but as soon as things get a bit more complex you need to reach for a separate library to make it easier. Unfortunately all of the popular options make use of weird patterns like reducers.

I ended up rolling my own state management that lets you just write a normal JS class with normal fields and methods and use that for accessing and modifying your state. No reducers, atoms, stores, etc... Just a JS class for your state and logic.

https://github.com/facepunch/react-class-model


One trouble I see with React is that it doesn't have a complete answer to state management. I was building very complex AJAX apps around 2006 or so such as knowledge graph editors and decision support software using tools like GWT and Silverlight that had the same async comm as Javascript and was developing state management systems that were so far ahead of React, Vue and that sort of thing that when I came across those frameworks I was seriously disappointed.

I've got the feeling that I can render anything I want the way I want with React (even 3-d worlds!) but the only framework that comes close to what my old systems could do is

https://mobx.js.org/README.html

and I cannot understand why MobX isn't more popular than it is. (Worked fine for a websocket-based app to control my smart speakers, it was trivial to make it so adjusting the speaker volume through the mobile app or buttons was reflected on my web app. Never tried a bigger app)


MobX can be slow. Example for me, and maybe I just did it wrong. Made a photo gallery viewer (so a page of a few hundred thumbnails). Have options in the toolbar for whether to show the filename, date, location, on each thumbnail. Use MobX to make those settings reactive. Result, it runs way way way too slow since each of the hundred thumbnails is doing some complicated check to read the value of the reactive state variables. I can fix that by having some higher level component (like the thumbnail gallery) read the value and then pass it down to all the thumbnails. But, the point is, I had to work around the fact that it's slow rather than just do the obvious thing and have each thumbnail look at the state it's interested in and not have to have higher level components deal with it. In other words, I want to be able to add features to Thumbnail without having to modify ThumbnailCollection but because it was too slow I now have to modify two places (or 3 or 4) instead of one.


Wonder why. We’ve got thousands of conditionally rendered components on a pretty interactive scheduling screen. One click can affect all of them but everything feels instantaneous.

Our bottleneck was that we have so much data, making it all observable up front led to slow initial load times and high memory usage. We now make things observable on demand which has eliminated a lot of that.


Try jotai. Of all the different react state libraries it’s the one I enjoy using the most.

I miss it when working with languages other than JavaScript.


I don't understand Jotai. What are atoms and why is using atoms preferable over a normal JS class/object? With react-class-model I can keep my data and logic in a JS class and access it from React components with hooks.


Atoms have a few advantages over a plain object:

1. They can easily provide derived data without manual memoization.

2. You can provide custom setters that do more than just assign values.

3. Your UI only re-renders the parts that reference fields that changed, not every component.

4. Atoms compose nicely etc.

Putting plain JS objects in context/state and passing them around only really works for simple, small apps. Beyond that you need more powerful tools. I also like Zustand for this.


For a bare object sure. Points 2 and 3 are solved with react-class-model. I don't understand how atoms compose nicely but classes wouldn't.

Zustand looks a bit better but it is still very different from normal JS. Nobody writes code like that normally. Why can't we have normal, boring code for state management?


This react-class-model?

https://github.com/Facepunch/react-class-model

7 stars on github? Class objects with decorators? No thanks.


That's the one. Obviously not popular since I made it for an app I work on.

What's wrong with decorators? Technically not needed but I like things being explicit.


> No learning yet another templating system (which inevitably morphs into a shitty programming language).

React has yet another templating language.

Sounds like we agree that JS isn't a shitty programming language, but that's hardly unique to react.


React doesn't have a templating language, React has syntax sugar for JS function calls - a very significant difference especially when you add TypeScript.


I haven't used React in about 6 years - used to be pretty heavily involved with it across web and native. These days I truly feel like ecosystem has lost its mind and the developers are just bikeshedding the most esoteric and unhinged choices possible.


I would have to respectfully disagree. React Hooks was probably the last "big" update to React and it totally changed how you build an application. The issue with hooks is you had hooks like useEffect that has very clear footguns that most seasoned developers knew but new developers would step on over and over and you also had optimization strategies with useMemo that weren't well known unless you've been around react for a while. Thing is with both of these is they can be automated with a compiler rather than having devs optimize it manually. My code has a ton of useMemo's and those micro optimizations and I estimate I can eliminate about 10k LOC assuming the react compiler does what it's advertised to do.


Contrary to what a lot of people say, useMemo is more than a performance optimization.

If React decides to create a new instance of a component because it thinks a parameter change happened all the state in that component can get dumped which can have effects like a bunch of selections in a combo box disappearing.


This does not happen. If you're losing state, it's always either because A: the component is replaced with another, B: the component is removed, C: you have given this component a key and changed it.

From your example, I think you've assigned bad keys, or forgot to assign keys (for which the linter will scream at you)


All the leading frameworks these days include their own compiler. This is just React catching up and eliminating a lot of the tedious and error prone dependency tracking you have to do by hand now with a tool that does it for you.


Why is it always people who haven't used React (or frontend dev in general) recently that feel the need to talk about how it's making "the most esoteric and unhinged choices possible?" All of the changes are solving problems that actual users of these frameworks run into.


> Why is it always people who haven't used React (or frontend dev in general) recently that feel the need to talk about how it's making "the most esoteric and unhinged choices possible?"

It might just be that, because they aren't married to the system anymore, they have a larger perspective than the people who can't see out of the system they are in.

The reality is probably somewhere between your and my extremes.


I have been building web applications for nearly 20 years. I have worked at every level of the stack and used every framework you can imagine. I have a lot of context on the situation.

I left React years ago for greener pastures for a reason.


I'm not saying you don't have the experience, but by your own admission you left React years ago, so how can you have context into what its current problems are and how they're being solved? Experience does not necessarily transfer across domains. It can, but not necessarily so.


And these green pastures are?


Vue!


What are you using these days, and how are you finding non-react work? I’m a front end dev with plenty experience and no fondness for react - but “3-5 years react experience” is a hard requirement for almost every senior dev position I see coming down the pipe. :/


ALL of these frameworks are 110% interchangeable. If I was a 100% vue shop (which we are), I would not hesitate to hire a React expert. Or vice versa. After a few weeks or months that knowledge will translate and before long that React expert will also be a Vue expert, or at least well on their way.

I would prefer a Javascript, DOM, Browser, HTTP, HTML and CSS expert to any framework specialist. These frameworks are ultimately a means to an end. The fundamentals matter the most. If you are intimate with fundamentals, everything else is just a walk in the park to map the fundamental knowledge to the frameworks approach or implementation.

I am not building Vue apps. I am not building React apps. I am building apps, and those frameworks happen to be one building block.

So if you know how to build killer shit for the web, I would not consider your lack of React knowledge to matter at all. You can pick that up quick.


I mean I’m with you, I can only assume the people reading my resume don’t see it that way. I assume when they’re choosing between “5 years of angular but react isn’t hard” and “5 years of react,” they going with the latter.

People keep telling me I just need to lie on my resume but I really don’t want to do that.


I think React would get better developer experience and performance if they adopt language coroutine feature to implement direct style algebraic effect. In fact the React Fiber system is already an implementation of algebraic effect.[1] However, it’s “suspending” a routine by raising an exception. Thus unwinding all the call stack, therefore, it needs to re-run that same routine on resume. This is the core reason why they have a performance issue and why they created the compiler to cache values on reruns.

JavaScript has language level coroutine features like async/await or yield/yield* and we have seen libraries using these features to implement direct style algebraic effect. For example Effect[2] and Effection[3]. You don’t need to memoize things if the language runtime can suspend and resume your functions instead of throwing exceptions and rerun them.

[1]: https://youtu.be/7GcrT0SBSnI

[2]: https://effect.website/

[3]: https://frontside.com/effection/


I feel like redux-saga [0] also belongs on that list of algebraic effects - at least as an honorable mention.

[0]: https://redux-saga.js.org/


In Rick voice: Well, that just sounds like generators with extra steps..


This is a Morty line...


What am I missing? You gave two examples:

The first is replacing useMemo with some inline code that does the same thing, so, as far as I can tell that literally saves just one function call to useMemo but none of the actual work it does? How could that possibly have a performance impact?

The second is de-inlining (or whatever the proper word is) map(x => foo(x)) to save function definitions on each loop. I don't understand why a "React compiler" would be able to do this if a JS JIT compiler can't, what guarantee does it have that a JS compiler doesn't? This should be done by V8 or not at all.

Even though you have a whole paragraph on the cognitive load of an extra compilation step at the end of your post, which is bang on, IMO you don't even come CLOSE to explaining why this trade off is worth it.

I've been telling people for nine years that React is the best of the declarative DOM libraries because it has a simple line-for-line transform instead of a big complicated compilation step. It looks to me like we're just throwing that all in the bin for absolutely fuck all.


I guess it's continuing the trend of patching over hacks with more hacks to try to work around fundamental design errors.

useMemo has the problem of having to specify dependencies manually and making fine grained updates difficult. Letting go of the unworkable pretension of effect-free components would solve these self-inflicted wounds, like is done in e.g. SolidJS.


> a whole paragraph on the cognitive load of an extra compilation step... IMO you don't even come CLOSE to explaining why this trade off is worth it

You're missing the whole context about how React is a library with a huge enterprise sponsor (Meta) who uses it to build some of the biggest web frontends in the world (Facebook etc.) where most of their engineering talent, like most enterprises, will trend to be juniors in order to save money.

Juniors will not naively get the dependency array for useMemo correct, period. With enough juniors banging away on enough PRs, especially if PRs are not reviewed by the most senior talent to save time, this becomes a problem at scale. The need to introduce extra compilation steps, especially when a codebase the size of Facebook already has (I'm sure) distributed build caching, is more or less immaterial compared to the savings of getting more PRs to be correct when first raised for review.


It's rather amazing and telling of our economic system that over a trillion dollar company can't make their main product work properly.


And that people tell mom-and-pop shops to use too, because Facebook uses it


People probably tell the shops to use it because they don't know anything else and lack fundamental understanding of programming which makes switching frameworks quite hard. I.e. job security for "React programmers".


Show me a better one... And please don't say Vue or svelte because these are just the same thing a little differently.


Depends on the use case. For a lot of cases you may not need a framework at all. A library like jQuery to smooth out DOM API horrors is probably a good idea anyway.

I'm not too thrilled about Vue or svelte either. But there are differences. Vue is more "relaxed" with state and effects, and svelte (and Vue 3) go the compilation route to keep the illusion a bit better. Both can get nasty quickly, with complilation hacks playing significant part.

For a current small project I started with Vue (mainly for Quasar) but switched to React due to Vue magic starting to break. Now useMemo is starting to get unwieldly, so probably switching to SolidJS or Preact/signals.


I was a web developer before jQuery, during jQuery and still am after jQuery. You really want react/similar even for very small apps. I went and tried to implement a simple calculator app without any dependencies just to see if it got better with Web components, but not really, way too limited to be useful for anything other than purely design tokens if you don't want to reimplement React. jQuery is not really necessary any more, the problems it used to fix are solved - but there is still no support to make a reasonably organized and performant reactive application.

BTW not sure what you mean with the useMemo - I built very large applications in React (hundreds of complex dynamic financial analysis pages) and didn't have much problems with it - could you go into detail please?


I was a web developer before XMLHttpRequest. JQuery is just a convenient way of using the DOM, and this has not been fixed (especially addEventListener is a horrid API, but many others too). If you're coding for browser, there's no escaping the DOM. Web components are an orthogonal thing. You don't necessarily need components at all to do web frontend.

React is a fundamentally different paradigm from the event-based DOM, but it tries to do a (leaky) stateless abstraction on it. You can have event-based APIs with different kinds of organizations. E.g. SolidJS is an event-based framework with component organization.

useMemo requires explicit tracking of dependencies, and it requires a lot of handholding to update just what is needed. Of course you can do practically anything with it, but it can get tedious and error prone.


The problem is more with us than them.

We lap up all the open source and ideas that the FAANGs of the world put out and presume they are awesome because...it is hard to get hired there? People've heard of them? They pay a lot?

It's all political bullshit instead of actually doing the hard work of evaluating the idea and implementation.


The problem is network effects (everybody else is using it), anticompetitive behavior (e.g. buying out competition) and corruption (e.g. lobbying).


What's this we shit? I've been saying this since all this garbage started dropping way the hell back in the days of yore. I fucking hate all of these stupid frameworks with the burning passion of a dying star. We know how to build websites, we know how to build software. I have never learned these stupid frameworks and I have no intention of doing so, if you want a website, I'll build you a great damn website and no maybe it won't be web scale or able to handle sixty quadrillion connections, but it'll work, it'll be on time, it'll be under budget and you won't need a comp-sci graduate with 12 years of industry experience if you want to change what color the fucking buttons are.


what do you propose they do instead to reduce bugs?


By mandating that people can access their data so less incompetent organizations can create less buggy systems with it.


Studies have shown that number of lines of code is directly proportional to the number of bugs produced in that code, regardless of language or framework. Would it stand to reason then that a framework (yes, I said it) like React with its boilerplate is suboptimal, even with the new compiler?

As an old school web dev, to this day I cannot understand how multi-megabyte JavaScript code blobs (after gzipping!) became "normal" and acceptable.


React with several big libraries is still only 100k or so gzipped. I'd say it has less boilerplate than most other frameworks too, especially when compared to something like angular.


1. React doesn't have less boilerplate than the average let alone most.

2. You haven't seen Angular lately, have you? It's on 18 now. 15 and 16 really trimmed things down.


A basic React app is 3 lines of code with an optional but recommended compilation step. You can get a very complex app with 20% of the code compared to Angular. Nothing else of the big ones (React, Vue, Angular, Svelte) comes close. Just don't use bloat like create-react-app, instead make an empty folder and install react and react-dom yourself.


What's the smallest "Hello ${name}" hooked up to an input field you can make deployable in React?

Svelte's is about 2.1KB last I checked. Can React get below 40KB?



Note that this is the full package, and that it's normal to use a bundler that will treeshake things you don't use away. For example react-dom includes server-side rendering functions that are not necessary on browser side.


Afraid that's not accurate.

The package size I linked is specifically the `react-dom.production.min.js` bundle that is used on the client side. The `react-dom` package does include _separate_ bundles used for server rendering, but that whole React client bundle will get included in your app, and it does _not_ tree-shake at all.

(To be clear I _like_ React, but it's best to be accurate about what happens here.)


So this package is not the actual react-dom package I get when I npm install react-dom? Thanks for the correction!


The `react-dom` NPM package includes multiple different JS bundles that are used for different purposes. See that `unpkg` link I pasted in the parent comment.

There's 3 different flavors of `react-dom` for use in the client (dev, prod, profiling), and then several variations of `react-dom` for use _on the server_.

The client bundles don't include any of the server functionality.

_None_ of the bundles are treeshakeable at all, because A) they're shipped as CommonJS modules and not ESM, and B) the way the React library is written and architectured as a whole. All of the reconciler logic is intertwined and unshakeable, so even if React did suddenly switch to shipping ESM modules instead of CJS, it would still end up as the exact same bundle size.


So how small can you get for a hello world page with a single "hello $name" component, spending an hour or less on it?


That bundle size + the size of your component.

Just created a fresh Vite+React app and rendered a "hello world" component, and the resulting output is:

    dist/assets/index-uoOveHrm.js   142.66 kB │ gzip: 45.76 kB


Go for Preact if bundle size is your concern.


I'd rather go to Svelte for lower bundle size than Preact, better performance than Preact, and clearer code with fewer lines written than Preact.

Sure, I'd lose access to the React ecosystem, but I'd also gain access to the vast ecosystem of vanilla JS libraries without having to write/use a wrapper, so that's a wash. (bind:this is awesome!)


Yep, sure! Personally I don't like the Svelte programming model, and I like Preact signals a lot, and hooks are fine to me. But Svelte is definitely a good way overall.


The big time/cognitive savings is in not having to manually keep track of what should be in the dependency array, which is what you have to do with useMemo.

I don't explain why the trade off is worth it because I'm not convinced the trade off is worth it. I'm explaining because devs using React will need to know, I'm not trying to convince that it's the right choice.


How does this compare with ubiquitous lint rules that require hook dependency arrays to be exhaustive?


Personally, I semi-regularly encounter instances where this rule must be ignored else I achieve an infinite re-render loop. Other times, it can be ignored, like when you use a stable value in the body of the memo or effect, like state setters from `useState`.

In practice this leads to ignoring the rule, disabling the rule with a comment (and potentially forgetting to add vital dependencies when the function is updated), or adding a bunch of unnecessary noise to the dep array.


Can you give an example? In my experience these cases are often trivial to fix, and React provides some solid documentation on how to solve these: https://react.dev/learn/removing-effect-dependencies

There absolutely might be cases that can’t be solved, so I’m hoping to break out of my bubble and learn what they are!


Fairly common: triggering a side-effect that uses some state value, only when a different piece of state changes.

useEffect(() => { doSomething(someState) }, [otherState])


Sorry, there might be a misunderstanding —- I’m looking for an example of when the dependency array needs to be [], is that what you posted?


The example supplied is what I was trying to get at.

An empty dependency array means that the effect runs only once on mount. Same with memos and callbacks -- the value should remain stable. Here's a real world example of how I populate some state based on url query params:

https://github.com/Naught0/combinator/blob/master/frontend/s...

I may end up using a more robust routing solution to keep in sync with query params if I ever want to spend the effort, but this is a naive solution that works alright.

A more simplified, generic example could be:

  const [foo, setFoo] = useState();
  useEffect(() => {
    setFoo("bar");
  }, []); // The eslint rule wants setFoo here despite the value being stable


Yeah maybe I didn’t follow exactly, I meant this as a common example of when the hook dependencies rules must be ignored.


To me the big winning is that you don't have to memoize transitively. Occasionally someone asks me for help to optimize some react code, and then the dependency array contains some object/callback that has a dependency which has a dependency which wasn't memoized.


> de-inlining (or whatever the proper word is)

The phrase you are looking for is "loop-invariant code motion". https://en.wikipedia.org/wiki/Loop-invariant_code_motion


The big problem is that

- memoization sometimes crucial for performance.

- passing objects and functions around is common.

- you cannot compare objects and functions for semantic equality

If you wrote larger react apps you almost certainly had to useCallback at some point so that memoization worked, the compiler fixes that.

Whenever you construct an object or function the react compiler memoizes on their free variables so pointer equality is sufficient.

Though I do think the compiler caches too aggressively, even if there are no free variables and hoisting is sufficient or escape analysis shows it is unnecessary for semantics.


>It looks to me like we're just throwing that all in the bin for absolutely fuck all.

Welcome to the last 5 years of React development. React was "finished" with 17, but it's now a zombie project being filled with increasingly absurd feature sets serving as a promotion tool for bored Meta devs.


For me the start of the decline was actually React 16.8 with hooks.


No accounting for taste, I suppose. For me, hooks were when React got amazing.


No accounting for taste, I suppose. For me, class components were absolutely horrid and hooks simply made it less horrid by comparison. I guess anything can seem amazing after you've been stuck in knee-deep mud.


Hooks were how they re-added necessary functionality to function components that class components already had. They definitely didn't think it through.


I mean, if you don't understand how specialized inlined code could be faster than a generic function, or how not creating temporary arrays could be faster than creating them, then it's clear that you can't see that there could be any benefit.

I can't judge the React compiler yet, but in general, compilation steps don't cause cognitive load if they work. How many different levels of interpretation and compilation does V8 do? And do you care? Do you have to? No, and that's the point. Whether React Compiler reaches the same level of "it just works", we'll have to see.


> How many different levels of interpretation and compilation does V8 do?

This part is key to the OPs objection. They’re saying that V8 is a very capable optimizer (which it is), so why can’t it optimize the things React Compiler optimizes? It’s a fair question.

> compilation steps don't cause cognitive load if they work

Personally I disagree. Any source code transformation adds cognitive load because my original source code now doesn’t match the source in the browser. Source maps are the traditional answer to that but if React is rewriting logic (like getting rid of arrays) you’re not going to be able to maintain a 1:1 source map.


> They’re saying that V8 is a very capable optimizer (which it is), so why can’t it optimize the things React Compiler optimizes?

Because capable != exhaustive? All compiled languages can benefit from further optimizations. I genuinely don't understand the issue here. Help!


I think OP is questioning whether these are optimizations or whether they are just redundant.

I don't know the answer - I don't use React personally.


The thing I'm struggling with as I read the official documentation and various blogs is exactly how this changes the developer experience. Do I get to remove `React.memo` and `useMemo` and never use them again? Is their use still useful for other cases? What do I have to think about when writing components so that I get this automagical memoization in some cases?


As I understood you will not need to use it anymore since that's automatically it's handled by this new layer. that's one of the const he mention on the blog, will be difficult to debug because that will happen under the hood.


I love how we're all talking about state management.

Just use Remix. The database/url is your state.

Messy state management in Client-Side react is a problem of the late 2010s


The app I maintain is a complex analysis tool that lets you build queries, explore data and create aggregate visualizations. The state doesn't even fit into URL, and connecting it to a DB... No thanks, that's be much harder and slower.


What do you mean build queries and explore data, all on the client? I'm curious


Yep, it can potentially download pretty big datasets and then you can explore them entirely client side using Wasm SQLite.


Slightly tangential question: Where is jsx defined, as a language? are there multiple transpiler implementations? is it standardized at all?


> Where is jsx defined, as a language?

https://facebook.github.io/jsx/ is the primary home.

> are there multiple transpiler implementations?

Yes. Off the top of my head:

Babel: https://babeljs.io/docs/babel-plugin-transform-react-jsx

Typescript: https://www.typescriptlang.org/docs/handbook/jsx.html

esbuild: https://esbuild.github.io/content-types/#jsx

> is it standardized at all?

In terms of well documented, yes. In terms of a TC-39 standard accepted as a part of JS and intended for browsers to consume? No. Unless you count how much it borrows from E4X [0] which was an optional part of the "lost version" of JS that was EcmaScript 4, then "sort of".

[0] https://en.wikipedia.org/wiki/ECMAScript_for_XML


JSX was unique while we didn't have native string interpolation in JS. With Template literals, JSX isn't that special anymore.


Don't know why you are downvoted (Stockholm syndrome, sunken cost fallacy?), but JSX is a bizarre hack, and there are many less hacky alternatives, like template literal based HTM, function based hyperscript and even const e = createElement.


IME "I'll just use createElement" leads to "Oh dear, I have to add another createElement" which leads to "I really don't like reading this code". But of course it's a trade off.


I'm doing a small project. I'm experimenting with a pure JS/HTML/CSS approach.

1. Doing "myElement.innerHTML = `...`" is sufficient for the low-hanging fruit that most jsx gets used for.

2. I also have a `Fluent()` function that returns an object with attrSet/attrRemove/classAdd/etc functions, which each also return the same object. It lets me do something like:

    var el = Fluent('div')
        .attrSet('disabled')
        .classAdd('waves btn btn-small')
        .idSet('MyNewElement')
        .push(Fluent('div')
            .attrSet('...'))
        .attachTo(document.querySelector('#SomeParent');
So far, I'm not liking the second one much, and the first one is really hard to compose, but they're both useful for when you don't want a build-step.


With coffeescript you can easily do with a dead-simple createElement wrapper something like:

  el = @div disabled: true, class: 'waves btn btn-small', id: 'MyNewElement',
         @div ...


I think coffeescript requires a build step. If I already had a build-step, then sure, I can throw a few things at the wall and see what sticks. For stuff that doesn't have a build-step, adding a build-step just to get an alternative to using the backticks seems like overkill.


How is that better than jsx?


It doesn't need a new language and has a lot less noise. Loops and control structures work normally without extra syntax.


Coffeescript is a new language though?


How is that different from adding yet another JSX tag which leads to another JSX tag which leads to even worse "I don't like reading this code."?

I admit that the parens and braces mess causes significant readability issues (though less than the tag soup). E.g. coffeescript gets rid of this problem very elegantly.

But, when coffeescript is discussed, it's "syntax doesn't matter, just use ES6" but when it's JSX, syntax is crucial.

It's sunken cost fallacy, Stockholm syndrome and FUD.


My time is currently divided between an Angular project and a "no framework" project, so it's been some time since I touched JSX but we are talking about the difference between:

    <MyThing><div class="thing--contents">"Hello"</div></MyThing>
versus

    const div = document.createElement("div");
    div.innerText = "Hello";
    div.classList.add("thing-contents");
    const wrapper = thingFactory(div);
Aren't we? It just adds up very quickly is what I'm saying.


I was referring to React's createElement-function (and assigning it to const e for ergonomics).

  const div = e("div", {className: "thing-contents"}, "Hello")
Or with coffeescript

  div = e "div", className: "thing-contents", "Hello"
Or with coffeescript and simple Proxy wrapper:

  div = @div class: "thing-contents", "Hello"


err... no?

Example using Lit and Template Literals:

  html`<div class="thing-contents">Hello</div>`;

Example using only web components:

  shadow.innerHTML = `<div class="thing-contents">Hello</div>`;


Right, JSX is not the only way of accomplishing a better syntax for dynamic HTML.

I was just saying that I do occasionally do things entirely by hand in Javascript with createElement, and it works for a quick thing but it is actually definitely a thing that warrents bringing in some alternative.


Personally I think "tag soup" (or, what I'd call a well structured XML document) is much easier to read than a deeply nested or scattered set of function calls.


Or you're just used to it. We get quickly used to e.g. our own body odor or halitosis so well that we can't smell it at all.


Of course. Isn’t that the case with any code?


Of course. But I sometimes try to smell some fresh air to check what I've gotten used to.


I must make a confession: I've honestly never understood why JSX is considered hackier than, say, template literal based HTM (or especially the bespoke pseudo-HTML you find in frameworks like Vue, which has always felt to me like the worst of all worlds). Is there a concrete reason I'm missing, or is it just a matter of taste?


I think it's having to extend the syntax so dramatically and bring new semantics to the language (actually a new language) and necessicating an extra complilation step for dubious payoff.

It makes the language substantially more complicated, with additional corner cases (e.g. className and htmlFor). For what I see as solely matter of (bad) taste (being used to XML syntax for defining elements, and abhorring extra backticks?).

The pseudo-HTML is not far from JSX in the hackiness, but at least it's embedded in HTML.


JSX as a syntax itself doesn't require `className` and `htmlFor`, it can support `<div class="example"><label for="someInput">Hello World</label></div>` just fine syntactically, that React API choice is a leak from the standard DOM API which use `className` and `htmlFor` for historic reasons (of bad parsers and stricter keyword parsing in earlier JS standards). In theory by using the DOM names React has less work to do when diffing DOM elements (though how much React actually benefits from it today is an interesting discussion).

(Possibly relevant source/proof: my TSX-based library supports the HTML shortcut names just fine, like:

`class`: https://github.com/WorldMaker/butterfloat/blob/cb9498354a7fb...

`for`: https://github.com/WorldMaker/butterfloat/blob/cb9498354a7fb...)


I'm still laughing about the fact that JSX renders to XHTML, not the HTML5 that browsers actually use. 99% of the time they're the same and parsing occurs as expected. That last 1%, things get weird quick.


Where did you get this idea? JSX doesn’t specify what markup it renders to, or even that it renders to any markup at all. The syntax most closely resembles XML (and therefore XHTML), in that it requires closing tags (which might be satisfied by self-closing with />). But this is an authoring constraint, it has no bearing at all on output.


So… you can use other markups seamlessly like SVG and MathML… just like XHTML. Walk like a duck, talk like a duck.


Not exactly seamless. You have to change some of the attribute casing in svg.


Huh? I didn’t say anything about what markup languages you can use.


Jsx doesn't "render to xhtml". Its syntax is similar to XML, but not the same. It's similar to HTML, but not the same. It's similar to XHTML, but not the same. In most react apps it renders to function calls like createElement or _jsx. The reconcile will turn these into DOM objects without any markup representation at all.


Do you have to close all of your tags? Yes. Is the markup based on HTML with XML rules like closing tags? Yes. Do you even have to close the tags of your custom components? Yes. When generating your createElement sequence from JSX, does it create or close tags in a different order/hierarchy than what you specified in the JSX? No. Does it emit markup or element creation calls that match the parsing behavior of HTML5? No.

Walks like an XHTML duck. Talks like an XHTML duck. It's an XHTML duck despite the JS interop and the lack of DTD preamble.


Does not have namespaces (in react), CDATA, schemas, and more. And none of this is "rendering".


The "reconcile" (my God do geeks love making what they do sound fancier than it is) does not match the HTML5 parser "reconciliation" spec. The DOM element API "emissions" match the order triggered by the markup parsers. Y'all are tiresome sometimes.


I legitimately don't understand what you're getting at.


My guess: It's probably downvoted for being so hilariously wrong that's not worth engaging with. One of those dismissive hot takes commensurately worth dismissing too.


These kinds of answers (and downvotes) typically stem from not having any substantive arguments for a held position.


https://facebook.github.io/jsx/ answers some of that.


JSX only have syntax defined but not semantics. The equivalent runtime js code is up to the compiler of the framework you are using (And even react itself have two compile modes now).


Not sure what everyone is so upset about. Since when is code optimization a bad thing?


I’m the author of this blog post, very cool to have it here.

One thing I didn’t say in the post: I’m very much a fundamentals-first kind of dev. I teach fundamentals in my courses.

I don’t think you should use tools like frameworks or transpilers/compilers without understanding how they work, because debugging is always better when you know what the tool is doing for you, and it makes it easier to use the tool. React is a particularly leaky abstraction that benefits from understanding it under-the-hood.

You need strong fundamentals to understand how things work.


I’ve worked with React, plenty of years. I haven’t had to touch it in months and don’t want to.

Seeing JSX and reading about all the complexity in this post makes me hope I’ll never use React again.

BTW I do like JavaScript.


For almost 10 years, the core react developers would repeat incessantly: React is a library, not a framework.

In the past 2 or 3 years, they just "gave" up, turned it into the biggest most bloated framework in the frontend area while the official Web APIs in the browsers evolved so much that React is actually completely useless and now it is completely useless with a compiler.

I'm wondering if that was actually the reason they pivoted to this Frankstein? The loss of relevance as a frontend library.

Anyway, I jumped off the bandwagon and don't have a say in this fight anymore. But I'm doing my part advising every Junior Developer to not make the mistake of choosing React today.


Is React irrelevant? Stack Overflow’s 2023 developer survey places it first overall for web technologies [1]. I’ve always considered React to be one of the more straightforward front end libraries, so it’s surprising to hear it being called bloated.

1. https://survey.stackoverflow.co/2023/#section-most-popular-t...


The fact that you have to go to often heroic measures to keep your bundle size under 500KB even for simple apps doesn't make it irrelevant or useless. It is indeed bloated: on the development boilerplate side, the bundling/deployment side, and the browser runtime experience.

With an experienced and top-notch developer, anything is possible in any language or framework. For the other 95% of devs out there—especially on a team where the lead doesn't keep a strong grip on the reins—React turns to mud awfully fast. But it's mud with an extensive ecosystem and tons of inertia helping it succeed.


You nailed it, this is exactly my experience.


> Is React irrelevant? Stack Overflow’s 2023 developer survey places it first overall for web technologies

Consider jQuery. It was extremely popular once; was super influential to the point that some of its apis were adopted by the browser; is completely irrelevant now; but is taking a long time to die. I've been wondering whether React is destined to repeat this trajectory.


The worst library except for all the others? The complexities are there for good reasons IMO; I also like React — and I look forward to the compiler allowing simpler code.


I strongly dislike React (not to be a hipster but I have for years!) but I wouldn’t advise junior developers avoid it. Like it not React is still the de facto standard, if I tell someone who doesn’t know better to avoid it I’m harming their career.


No, you are not. The complexity of a React app is pure madness.

The bloat in the ecosystem of (mostly) abandoned packages is unparalleled. With the bloat comes the need to tree-shake, bundle, compiling, things that are not needed in modern web development but takes a good amount of the dev cognitive load when developing a React app.

There are great alternatives nowadays that don't come with the bad recent decisions of React: Solid, Lit, even vue or svelte.


As you may recall I said I strongly dislike React. You are preaching to the converted with your complaints. That does not alter the fact that junior developer needs to know React since for better or worse (worse) it is the de-facto standard for front-end development at the moment.


I’m discussing tech, while you’re discussing anthropology. Should people use an inferior tool to achieve a higher social status/paycheck? I don't know, that's your opinion.

Do I recommend someone learn React to develop a web app nowadays? No, it's not worth it.

I'm not preaching to you, but to the juniors reading the thread. React contributes significantly to current JavaScript fatigue, and supporting it so juniors can get a job isn't in my or their best interest.


> I’m discussing tech, while you’re discussing anthropology

I’m discussing career advice. Something junior developers look to senior developers for. If your advice to your juniors results in them having fewer employment opportunities then you’re not doing a good job as a mentor.

> Do I recommend someone learn React to develop a web app nowadays? No, it's not worth it.

In what way is it not worth it? The majority of front end dev is done in React. Of course it’s worth it, even if it’s shitty.


FWIW I agree with you. I think in the Last "State of JS" and/or StackOverflow surveys, React usage was still like 88%+ for front end devs/engineers.

You'd be putting yourself at a disadvantage in the field (employment wise) not learning at least some basics. Especially if you're just trying to get your foot in the door. It's already hard to 'break in' but even harder in this hiring climate.


They don’t have the ecosystem that makes React worth it.


I jumped off and started using Svelte but have now found looking at job listings all the non tech companies are still using Angular and all the startups/tech centric companies are using Next.js.

I feel like from an employability perspective I shot myself in the foot, but I also dislike both of those frameworks. So maybe I should just quit being a front-end developer and try to retrain as something else.


I like Svelte too, but take another look at Angular. Your memories of Angular 9 don't match up anymore. It's A LOT more streamlined now with so much less boilerplate than before. And signals.

That said, transitioning to some backend or infrastructure focus never hurt anyone. It's good to see problems from different perspectives and roles. No one ever got fired for knowing too much SQL.


It's just a frontend framework.

If you already have fundamental web dev knowledge, you'll be able to switch between them easily.

That's why I like Remix. It's react + web fundamentals. I'm happy to jump into a Vue, svelte, angular project. It's not all that different


Yeah, obviously however if you don't have previous experience with a framework in your résumé, they're going to choose the people that do.


> advising every Junior Developer to not make the mistake of choosing React

I don't like react much, but I surely hope you advise them on ways to organise state management and rendering with good ways to track event listeners.


React is the premier frontend framework because it is easy to learn, scales ad infinitum, and has reached a critical mass where the library support is second to none.

Anyone advising juniors against learning React is shooting them in both feet, not least because of the demand for React developers.


Learn JavaScript first, then React. Far too many devs know the React APIs without any context. If you know JS/TS, any framework is learnable. If you don't, your React code will never improve past mediocre and bloated.

Strong foundational knowledge in HTML and CSS helps as well. Still amazes me how many folks put onclick handlers on div tags and freak out when margins collapse.


Fundamentals before frameworks. I've been a tech educator for a decade now, and still see this so much.


I am not a front-end developer. What are better alternatives to React nowadays?


Depends on your goals/focus:

Smaller, cleaner, and faster code while still focusing on dynamic interfaces? Svelte or SolidJS

Focus on server-side HTML rendering with little to no browser dynamism? PHP (It really is quite nice now.)

Focus on server-side HTML rendering with some browser dynamism? HTMX + server framework (PHP, Django, Go templates, etc.)

Getting a job as quickly and easily as possible, especially at larger companies? React or Angular (You're a cog in the machine, but cogs often get better paychecks to deal with multi-megabyte code blobs.)

Can't decide between code elegance/performance and finding a job, so you're willing to compromise a little on both? Vue


React really is pretty good as long as it keeps evolving. Innovations tend to come from new frameworks such as Svelte and SolidJS, and then React adopts them — this new compiler is an example.

React is hobbled by the need to retain backward compatibility, but it is boosted by sheer scale and a solid underlying philosophy, design, and engineering.

Someday, we will probably find a fundamentally better philosophy for UI frameworks, but I don't know yet what it will be. React replaced its MVC predecessors with a functional approach, the Flux model.


Lit?

AFAICT, if you pick any of the others options you'll have to refactor your site every 3-4 years as all the tools bit rot. One won't run on the latest version of node so you upgrade node. Now 2 other libraries fail and require an upgrade. Now another library fails because it's not compatible with those upgrades, repeat. You thought you were just going to fix a bug or add a small feature that would take you a few hours but now you've got few days/weeks of refactoring before you can even start.


I'm with you on that. Lit is the way to go. It is in the 3.x version but it never released a real breaking change but also it doesn't carry bloat for compatibility as it is a thin layer on browser APIs. The core dev team is great too, not looking to jump the next hype bandwagon.

WebComponents are the future (and the present) of web development.


Lit, for sure.

Now is WebComponents prime time. Libraries like Lit have just a little bit of code that makes the DX of webcomponents be top notch. Some people like to use TS with it but what I love about lit is how powerful it is with just vanilla JS and no compile/bundling/building phase. Development directly in the browser, sane stack traces and faster than anything I've seen.

Lit code is similar to what React was until the 16 version.


No... You should learn the most popular frameworks. Why just react? Build the same project with svelte, Vue, angular. You'll learn a lot which applies across any web framework, that's more important.

If you're messing around and having fun, sure learn some hipster frameworks.

If you want to have highly saught -after skills years from now, basic web Dev with most popular frameworks on top is by far the safest bet.


You should at least google (or ask chat GPT?) about Lit before calling it some hipster framework. Lit is the old Polymer.js and being under development for the past 10 years. Still small, still making the best use of web standards.

I agree with you about knowing a bit of most popular frameworks tho, they are quite interchangeable and very often adopt each others famous features. The biggest advantage of choosing Lit as your main tool is that it is the one that is more integrated with web components that won't go anywhere, anytime.


I know what lit is, a former colleague tried to pitch my manager on migrating to it because he too loved web components and we were investigating microfrontends.

Turns out, it's quite trivial to publish react and angular components as web compenents.

That completely took the value prop away from lit, and in terms of DX and library support, the other frameworks won easily

I'm not saying don't use smaller frameworks. I'm saying the safest future bet is learning the big ones


Vue 100%


>For almost 10 years, the core react developers would repeat incessantly: React is a library, not a framework.

I always disliked the it’s a library not a framework debate. Isn’t any library a framework, technically?


You call a library as you see fit. A framework calls you.


Oh yeah. I guess that's why we always invoke function components directly. Because it's a library.

/s


What do you think you're doing when you call render(<App />,...)?


Not calling App. Creating a react element with a reference to the function. The reconciler will call it later, asynchronously. Put in some console logs and see the order of operations for yourself.

Also, try calling App and see what happens if it uses hooks.


The createElement function is called immediately, and it immediately calls your component function. I don't think this is a significant difference. Many libraries accept a callback and I'm really not ready to call all that a framework just based on that.


createElement is immediate. The component function call is not. It may never be called. Try const a = <App />;

App() will never be called.


Yeah, it will be called when you call render as in my original comment. Again, I don't think that passing a callback makes a framework.


When you combine that with the fact that you can't invoke the function directly, this seems like the textbook definition to me. Agree to disagree I guess.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: