Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
How to Use React Compiler (freecodecamp.org)
49 points by amalinovic on Aug 31, 2024 | hide | past | favorite | 30 comments


The compiler is interesting.

I was expecting it to analyse dependencies and create automated useMemo calls around everything. I mean write regular, readable React code someone might write manually.

It does not do that, instead it creates a cache context. Something like a single useRef object and writes imperative code to check if a dependency has changed, look up the previous instance of a variable from the cache and use it etc. Also caches JSX segments and stuff.

This would work much faster I guess and would be easier to extend.

I assumed the svelte / solid / vue way of reactivity was the way forward for granular reactive apps. Avoiding unnecessary rerenders etc but the React compiler does a really good job and you get all the fine grained reactivity benefits for free. Without thinking about it in the code.

Optimizing compilers are neat.


The one place where signal based fine-grained reactivity still wins are lists.

Updating the "done" state of a single todo item nested in a list of todo items still causes an entire list (of possibly hundreds of items) to re-render.

In principle you can solve this with fully normalized state shape but in practice things like MobX (especially when combined with SolidJS) still provide the best ergonomics and separation of concerns with very little compromise.

I'm however excited to see what kind of DX improvements the compiler can bring to the table. Perhaps someone will have a good idea and we'll get something that's at the level of MobX.


Ok haven’t tested this but assuming a naive implementation of an array of 1000 items and setting completed: true in one of them by updating the array would trigger 1000 calls to the inner components.

If the react compiler is used, 999 of them will return their memoised result. 1 will need to be rendered again.

Which has an overhead but is still a huge gain compared to actually creating vnodes and diffing all render results for all items.

You are right, in case of fine grained reactivity, this could just trigger a render on the specific item. But for that to work, the framework will need to wire up 1000 subscriptions to prop changes, have proxy objects and shit like that. There is a larger initial overhead for that and the memoisation + brute force approach might be better at the end.


The setup / overhead is for the initial render, but after that I'd be surprised if O(N) defeats O(1) even with a bit of a bigger constant (given a sufficiently large N). Also, given React Fiber, I doubt that those 1000 calls will simply be function calls - I'd expect plenty of overhead on that end too.

Would be interesting to design a realistic benchmark around this. IIRC Michel Weststrate (the author of MobX) had a realistic example based on draggable elements on diagrams, where the diagram link lines needed to be recomputed in realtime as you drag the boxes around.

Another realisitc option would be large dashboards made of tables where lots of data updates come in real time.


If TC39 Signals are merged this will be redundant. Signals are better than this as they keep track of the tree and don't do unnecessary traversals. With 'automatic useMemo' (this), the tree still needs to be fully traversed.


That’s a great write up. I’ve been using SolidJS and hadn’t taken the time to soak in the compiler information, so this was a great time saver.

Although it’s nice not to worry as much about these optimizations (and I’m certainly not trying to put down the work that went into this compiler), something rubs me the wrong way about so much code generation sitting between the code I wrote and the state management I intended it to do.

I guess it’s because react has bitten me so much in this department in the past. I’m sure it’s smarter than I am, I doubt it’s wrong as often as I am, but it feels like it could potentially obfuscate issues or cause slight quirks that would be really, really difficult to debug. Of course it’s just an initial reaction rather than a rational concern based on an intimate understanding of the compiler.

Having said that, what the compiler does is different from what I expected but much simpler too. It’s easy enough to follow what it’s doing.

I’d like to see performance comparisons between apps with good state management practices without the compiler vs the same apps with no special state management and using the compiler. Is it worth this added complexity if you’re already familiar with React’s foot guns?


Maybe I'm more risk tolerant, but I'm not so concerned about the compiler doing things that I didn't tell it to do. GCC and LLVM heavily rewrite code and it's generally rare to experience compiler bugs. Uglify/Terser very heavily rewrites JS, but you can still step through it with the help of source maps—sometimes without even noticing it's been compiled. Babel and others rewrite async functions into code that looks almost nothing like the original code (but runs in older browsers) and introduces a whole runtime library for executing them, but we don't even think about that.


I worry about this too but I guess it all depends on tooling/debugger - in native land this days you trust compiler and debugger and even code is in ASM everything just works so in react land this still should be possible to deliver similar experience.

Similar trends is in other declarative frameworks even on native such as SwiftUI - its easy to write complex gui but harder to debug and easier to shoot yourself in the foot. Its just harder to reason how declerative code will be executed in all corner cases and you have to trust compiler will do its magic. Overall for me it seems a lot of SwiftUI app feels much slower and even Apple developer from time to time shoot themself in the foot. We are just trading developer experience with performance and debugging.


I think the article misses one of the central points behind having a compiler:

It's not about managing memoization in an automated way - even though that's also very nice - but rather the ability to compile closures and package them.

This way you can automate hydration.

The main pain point with SPAs is that you're generating huge packages since you have to ship all of your code at once.

Having a compiler gives you the ability to do tree shaking on a per-component basis.


Is that a reaction to Svelte, Solid JS etc?


...finally?

This kind of automatic optimization was one of the reasons they pushed for function-based components ~6 years ago over class-based components. One of the main points was "you'll no longer need to think about shouldComponentUpdate()".


As someone who mostly works with standard OOP libraries / frameworks (Lit and Flutter) I’ve always thought that the overwhelming MAJORITY of the arguments that came out of the React camp regarding why functions are the path forward were mostly just bullshit and after sitting on that for several years now I think that has held up fairly well at this point.

I quite regularly find myself looking over the fence as it were and genuinely can’t believe people would willingly work like that with the insane levels of complexity and nonsense that the React ecosystem has become in recent years.


How so? For me, modern hook-based react is the most pleasant way to write UI's I've ever used — and I used to do a lot of different UIs on different platforms. And transition from classes to hooks was an incredible improvement as well. When you read a function body, you know that declarations can only depend on previous ones. This makes it much easier to read and reason about the code, compared to a class body, where each member can access any other. This also makes it much easier to extract different pieces of functionality into separate hooks.


What else have you actually used though?


Visual basic, Delphi, win32, flash, imgui, Unity GUI, iOS (Objective-C era, first half of 2010s), Android (also first half of 2010s), even curses, WPF. As far as JS frameworks go, raw jquery, Angular, React. When I was first learning HTML, the best ways to lay out a website's structure was to use a table, often — with heavy use of iframes, so I can compare that to modern web development too.

And I wouldn't write complex modern applications in anything else, unless there's computationally heavy rendering going on. And even then, I would still try to keep other parts, like slower and not as expensive to render UI, in this paradigm.


I don’t mean this with any snark at all because I’ve also used a bunch of those that you listed and remember those old school days well but I don’t think they are a fair comparison to modern approaches and I can see unironically how React would look great in comparison to them.


What are some of these modern approaches? Vue, Svelte don't feel like that.


I think Flutter or Lit would be a fair comparison in scope. They are both just UI focused, they run in the same environments, they both took two different architectural approaches but kept the same 1 component = 1 class model and both incorporated lots of similar ideas about how OOP can best be used in UI design.


QML, Slint and their property bindings come to mind (regarding "manual dependency tracking is a pain" elsewhere in this discussion)


Svelte 5 comes pretty close.


Disagree. Hooks with all their warts are superior way to share functionality over anything found in the class land.


I find it weird that it’s supposedly such a huge improvement and yet people don’t seem particularly keen to copy the idea into other serious frameworks for the most part.

Looks vaguely like Stockholm Syndrome from the outside


Because hooks are both a great innovation and a pain in the ass at the same time. They make reusing and composing logic between components easier than any other framework I've used.

But all the manual dependency tracking is a real hassle and is crying out for language-level support, to which this compiler brings us a step closer.

Hooks do seem to be gaining some traction in Flutter, FWIW.


Yeah, hooks totally suck—no question about it. There simply aren't other facets of other front end or back end frameworks that are so widely criticized to the same level that hooks are. Which means they're at best controversial, and at worst they're a poor design choice and add mud and confusion to the framework.

I find that hooks are fine when you want to do simple web-app stuff, like fetch from a db, post some data back. But once your effects get more complicated, like using web sockets, items with retries, play or queue async audio clips that have to be state managed with hooks—the house of cards comes crashing down and they are an absolute nightmare to work with.

They're such an anti-pattern that useRef has to be repurposed from a thing that was meant for holding a reference to an HTML element to a new thing that is used to hold state that doesn't trigger a lifecycle update—and there are many paradigms that you can find yourself in where the only path forward is to use refs, along side and inside of your otherwise lifecycle updated hooks. What kind of cluster f*#& is that.


It will sound like “you’re holding it wrong” argument. But most issues I heard about hooks is when people don’t isolate their React UI modules from other modules in the application. Instead they use the library/platform api directly in their components which is guaranteed to be a mess. Hooks are way to integrate your UI with the rest of the world, not to manage it. Things like using web sockets, playing audio, etc, should be in external modules which you connect to with hooks, and those modules should be designed with React lifecycle and state in mind. An example is react-query, which does a great job of adapting “fetching from an API” use case to the react world.


I’ve recently had to work with React after years away. When I’ve done web UI in the last few years I’ve used Svelte.

I honestly can’t believe everyone willingly marched into this weird hooks land. I’m sure you get used to it but compared to other frameworks it’s such a chore. The more I use React the more I feel like the maintainers deliberately make it different from other stuff so that people get trained in “React” rather than “JS” and it becomes its own world.


that’s easy just call useReactCompiler

/uj


The react compiler is so cool!


The autumn is cool, not a library.


Lame




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

Search: