Hacker News new | ask | show | jobs
by Spivak 1798 days ago
The problem with React (or the reason you might want to sometimes choose VanillaJS) is that React's algorithm to apply a DOM diff has to be completely generic. In React your flow will loosely be

    Something happens
    The browser triggers and event and sends it to React
    React calls your code to re-render the world[1]
    React takes the new world order and does a diff
    React calculates what to do go from old -> new and applies
In VanillaJS world you can do way way way better than this with the benefit of knowing how your application works.

    Something happens
    The browser triggers and event and sends it to your handler
    Your handler updates the DOM
It would be nice if in future you could make some promises to React about what happens on an event so React can skip the diffing step and just update the virtual and real DOM directly. And hint hint if you can generate the code to update the DOM directly in the general case too then do you even need the virtual DOM? Svelte is doing really cool work in this space.

[1] componentDidUpdate helps but same diff

4 comments

The whole point of react is to avoid the stateful nightmare created by the latter approach. When given Y, render X.

I'm glad it's not easy to escape the paradigm.

I know there are cases where it's needed but it's rare (at least in my line of work).

> The whole point of react is to avoid the stateful nightmare created by the latter approach.

I found this ironic, as I have never in my life had more struggles with state, than when working with react native. Seriously, the amount of times something didn't update, or was updating way too many times, is countless. It's so easy to shoot yourself in the foot. Imperative native programing, almost never have this issue.

You could try angular then, though at some point you're going to run into a similar problem: your zone not becoming stable (mostly a problem when writing tests) because of some external dependency using a setTimeout or setInterval*. But at least it's generally pretty fast at updating and works without shoehorning you into one way of managing state.

Overall I prefer React because I prefer simple composable libraries over frameworks and Angular reminds me too much of programming in Java with its long application boot times and its folders full of ListUpdateCheckerConditionFactoryBeanUnitTest.java's.

*To be fair, in an equivalent React app, at that point you would have had to write a whole lot of shouldComponentUpdate to not tank performance.

Of course! The takeaway is that in the future it would be nice if you could have the best of both worlds by being able to compile some DOM transformations ahead of time and/or have React observe and JIT them so you can bypass React's machinery most of the time while getting to pretend its there. It will feel like a re-render but it's actually just a direct DOM manipulation behind the scenes. That's Svelte in a nutshell.
The future is here and called SolidJS
Solid seems awesome. Though as a Svelte dev, the jsx / React flavored api felt like a regression from the simplicity and readability of Svelte’s template syntax. Have you explored both in depth? I’d be curious to know Solid and its ecosystem compared to Svelte and Sveltekit .
The point is that in real applications it is really hard to get the update logic straight.

The React haters here seem to think that is easy. But most of the popular frameworks/libraries use a virtual DOM in some way or another. And Svelte also automates handling the updating. Maybe it's not so easy after all, if smart people have spent decades trying to find alternatives.

The beauty of the virtual DOM is that it relies on pure view functions: given this props+state input, this is how the DOM looks like. Generating DOM fragments on update is possible, but naively done it will quickly get out of sync with the DOM view function. Curious about 'really cool work' in this space!
> Generating DOM fragments on update is possible, but naively done it will quickly get out of sync with the DOM view function. Curious about 'really cool work' in this space!

This is what Svelte's doing, as I understand it: letting you think like you're writing React ("when in this state, the world should look like this") but avoiding the (greatly overstated, IMO) overhead of the virtual DOM by translating the changes into direct DOM updates in a complilation step.

Virtual DOM overhead is only overstated in that it usually isn’t really compared to any reasonable baseline when discussed. Many will acknowledge that React was faster than many of its contemporaries—and I’m sure it remains competitive—but still express concern over the unnecessary overhead of the virtual DOM.

I think I blame part of this on the language we use. These days a huge buzzword of sorts is the “zero-cost abstraction.” It means zero runtime cost, but a lot of us internalize it as completely free, failing to account for the fact that it often entails increased complexity and build times. Granted, often this is a worthwhile tradeoff, but in order to know you need a more nuanced comparison. That virtual DOM is “pure overhead” isn’t objective fact - pure overhead is an error of coding that can be fixed in a pull request. No, this is more like ideology.

The problem with this ideology isn’t that it’s bad, it’s just incomplete. It usually explains away why the world hasn’t simply adopted their worldview by appealing to ignorance or even stupidity, while ignoring potentially serious issues. Like yeah, if I want to make a desktop application in 2021, I have to consider Electron because simply put, there’s a lot broken in modern native UI.

And sometimes people are still right. There’s always a possibility Svelte will win out, or eventually be proven right even if it doesn’t.

Maybe. But it’s 2021, and the year of the Linux desktop is still around the corner. If something hasn’t happened yet, at least humor some reasons why that might be the case.

(Personally, in my experience, even update-intense apps wind up having bigger fish to fry than VDOM, so I can’t say I’m holding my breath.)

In practice, React users often end up running all their app code through a big slow compiler anyway. Usually Babel (to convert JSX to createElement calls) or TypeScript. Svelte doesn't increase the overall complexity of your build process, it just uses that compile step to do something to your code that's actually useful.
Adding more compilation steps is not free, though. You have to convince people to want this. It's not necessarily an easy sell.

Even though JSX is pretty React-specific, it still has managed to make its way into other frameworks and many compilers because it's fairly general at its core and because it is a fairly non-invasive process. So for example, you can compile JSX using babel, but also TypeScript, esbuild, and more. (And those are all independent implementations!)

I can't claim to know what the build process looks like for Svelte, but I have a suspicion it is far less general than the source code transformations that we have so far that provide type checking and newer ES functionality in older engines. (Which, by the way, you appear to be insinuating are not "actually useful.") Angular has a similar thing going on and it is not terribly well received.

Type checking and Browser compatibility are somewhat useful to some people...
Virtual DOM overhead is totally overstated. It's just that it offends some people's idea of efficiency to build a data structure to throw most of it away anyway.

But in reality, the virtual DOM allows you to avoid manipulating the actual DOM, which is both slow and error-prone. The browser necessarily attaches all sorts of memory objects and state to components in the DOM, which his why unnecessary mutating has to be avoided at almost all cost.

Svelte may go a step further by automating DOM manipulation. But it doesn't have the same following yet. And usually, if there is no explosive growth in such a technology, it's not just because of evil overlords preventing its justful rise...

You do know the vdom eventually has to change the DOM right? In the end the vdom always will have to do more work than regular dom manipulations.
vdom has the potential to do optimizations that simply aren't possible in individual functions because it sees the whole DOM at one time.

There's also the preact method which diffs against the DOM directly, so that overhead goes away.

Do you remember when InfernoJS broke the framework test? It blew away 2-3 versions of vanillaJS with it's vdom implementation. They literally tore apart what it was doing in order to finally create a vanilla version that was faster, but very unmaintainable.

Today, "native" frameworks like Svelte are only fractionally faster at synthetics. At the same time, each component contains a brand new set of functions which has two major drawbacks. First, code size grows at F x N (where F is framework size and N is your normal code) rather than F + N. Linked to this is the performance implications. Once the JIT warms up the vDOM code (almost instantly), the user gets max performance for the most critical loops when visiting pages for the first time. With "native" frameworks, each new page means switching back to completely unoptimized code.

It is theoretically the case, that a virtual DOM implementation has to do more work than a perfectly efficient manual (or automatically generated) DOM mutation.

However, in practice the difference hardly matters and it is really hard to do efficient DOM mutation correctly. Which is why virtual DOM approaches are at the heart of most of the modern frameworks...

Ah, I see. The programming model is similar, but the execution of the virtual DOM shifts from runtime to compile time. Cool!
Like I did in another subthread I’d suggest looking at SolidJS. It’s philosophically similar to React for rendering, uses JSX, and at least as “pure”. It has reactive APIs similar in use to React hooks (neither of which are pure), but compiles to DOM.
SolidJS is doing this at the compiler level. JSX components become DOM nodes and its underlying reactive primitives.