Hacker News new | ask | show | jobs
by QuadrupleA 1804 days ago
Ugh, this is massively overcomplicating the vanilla js case.

Just put the checkbox html & css on the page. Write a function that updates the label based on checked state. Call it on input/change events.

It's like 3 lines of js.

React.js people always invent this vanilla js / jQuery strawman that's so complicated and spaghetti that no mortal can possibly understand it.

It's total BS. You can write succinct maintainable code without a 100 lb framework.

11 comments

This is true. We recently re-wrote everything in plain javascript from react, and it didn't increase the lines of code.

The vanilla code was much easier to maintain too. React comes in your way when things get complicated and the work arounds produce really messy code.

Edit:

Project (GitHub): https://github.com/labmlai/labml/tree/master/app

It's a mobile/web app to monitor machine learning experiment.

This gives more information than any other analytical comment. Someone who has used both to build the same application and can compare the experience between both.

It's not the final say. Just a strong signal among many others.

Without context like what this application does or how many lines of code you are talking about, this means exactly nothing...

Also there is nobody stopping you from writing extremely messy React applications...

It doesn't look like a very complex application, but already has a ton of abstractions, essentially building your own, unproven and unreviewed framework.

Also I think you got a typo at https://github.com/labmlai/labml/blob/master/app/ui/src/view...

Thanks for finding the typo.

Ton of abstractions is an overstatement. https://github.com/vpj/weya is more like a helper function around `document.createElement`.

A function is an abstraction. A JSON object is too. Are we in preschool here, not allowed to create new abstractions because they're "unproven and unreviewed" by a FAANG?

This all seems so narrow and parochial, like people who have never left their own village. There's a wide world of useful technologies and design techniques out there (including React) and the simplest possible design that solves your problems is usually best.

You are allowed to do practically anything. I'm just stating that I don't think it's an improvement to replace battle-hardened well understood abstractions for half-baked new ones you have to learn on every new project.

People running away from "bloated frameworks" very often end up reimplementing a significant portion of the bloat. But usually with fewer ressources and fewer testing, so you can guess what happens most of the time...

Cool.

Project Manager: Now add 3 checkboxes, one being 'N/A' and when you select N/A the other checkboxes are disabled and unchecked. And update the labels, and have additional form sections showing depending on which checkbox is displaying.

Probably not that difficult, and probably a bad example, but with React/Vue/etc. it's a lot easier to deal with complex states than manually manipulating the DOM.

From experience trying to be clever and anti-framework ends up just creating another framework that's worse in every imaginable way.

Hum... Your new function reads all the checks, calculate the new values and enabled conditions, and applies them. It's called by the onChange of all of the relevant elements.

Reactive frameworks do make your life simpler (at least once you pay for the large one time cost of using them), but the change isn't enormous.

Or you just use React and it has that function already built for you...

All you need to do is call setState

You certainly doesn't mean that React has your business rules builtin.
No, but it'll deal with changing the UI depending on your state once you've wired the rules in.
> clever

Virtual DOM qualifies as clever in my book. :)

Better question to ask is why so many libraries/frameworks proliferate in webdev and not as much in native apps. JS is a suitably powerful language these days.

Also, the attitude of “just use jQuery like everyone else” (paraphrasing the last paragraph and substituting for React) would have precluded the development of React.

The cleverness is abstracted from you as a developer and the cleverness is maintained by an open-source community and a huge corporation (Facebook).

With native apps you definitely have frameworks available now. React Native for an example. But the languages and toolkits available basically serve as a framework anyway.

Is cleverness only allowed for the FAANGs of the world? I cannot subscribe to such a nihilistic view of computation.

SICP should be required reading for any serious dev if only to expand their imagination beyond an industry that is intensely focused on boiling the difficult and creative endeavor we call software development into a discrete, repeatable process.

I mentioned the open-source community in my comment. So a collective of knowledge of many talented developers from the public, and also the stewardship of a FAANG and their developer talent pool also.
is that how react was invented?
And they also end up with a lot of useless framework knowledge they'll never use again after the project goes up in flames.
Well react itself is just the virtual diff algo really.

How to change this page to this other page as fast as possible, if you don’t know or don’t care to know that other page.

That second qualifier is really important. As long as you have 2-10 screens and know the transitions by heart, nothing stopping you from hand rolling js. But once you start adding states things get tricky really fast, as transitions grow exponentially.

I’ve built some very complicated apps with vanilla js back in the day, and we had ways of dealing with things like that. We called it “reloading the page” where you start from 0 with your state. Kinda like restarting windows to fix it, rather than figuring out whats wrong.

And you could get quite far that way. 37signal’s basecamp was like that - an html app with vanilla js sprinkled throughout. Worked great.

But there is a limit in complexity. JS and html are great for building websites, but if you want to build an actual application, you need to be really clever and accept a lot of limitations. React just lifts the ceiling of what you can do, without being all to complicated.

And you can use the technics of react without react itself too, once you understand what it is all about - https://github.com/ivank/vanilla-teuxdeux

Why do the virtual dom thing at all? Just remember the locations you need to update and update only them, like svelte or lit-html.
Why is it relevant? The point is you are not the one needing to remember.

One day React could change from using Virtual Dom to the Svelte way and most user of library wouldn't notice.

The point of the article is that React remember where to make the modification for you.

It seems like it's a non-effective way of doing it. In large DOM trees you need to manually interfere to make them update fast because (1) building even the virtual DOM and (2) then comparing this to the real DOM become slow => i.e the "React way" doesn't actually scale. Perhaps for a product guy this doesn't matter, but for an engineer it just feels wrong. Why not solve the real problem?
Because the real DOM exists in a separate world where you have to cross a trust boundary. The vdom is an implementation detail of React because the real DOM is too slow to traverse to diff on every render. Think of it like this.. jquery is a wrapper around a querying API, so it’s like running a sql query that can be indexed in a b-tree or a hash map, because you query by id or class or some other attribute. React on the other hand needs the entire state, which is equivalent to a select *.

If you say why does react need the whole state, it’s because React is a translation layer between an immediate mode representation and a retained mode system (the DOM). To illustrate this in a basic way, think of a checkbox. It is an entity in the DOM, but it is also retaining state itself (there is a Checked property that persists as long as it is set, so you know it has state). The only way to know if that checkbox is checked or not is to query the DOM to get the checkbox entity, or to “control” the rendering of the component so you can always derive the checked state from somewhere in your code, and force its state to match. React controlled components are a way to express unidirectional state from your code to the UI.

What situation were you in where vdom was the problem? I’d love to see an example. It is likely that vdom was not the performance issue, something was wrong with the implementation and causing a full re-render. Could you link a sandbox?

I understand why it's convenient to derive the UI from the state, no need to explain that.

But what react does is: for any change in state it creates the entire virtual DOM" regardless of if there was a single checkbox change and everything else remained the same. Then it compares this whole tree* to the real DOM, and then only replaces the parts that changed. The "win" of react is that instead of rendering the entire real DOM again and again it just renders something that is not seen and then swaps out the changed parts in the real DOM.

Why not short-circuit from changes in state to real DOM instead?

I think any google sheet like app would do: you type into some box, this changes state which triggers the creation of the virtual DOM for the entire sheet. Then it compares this entire sheet to the real DOM, finds that only one cell has changed and swaps that out. There will be one entire virtual DOM per character typed. Which is why I'd presume most if not all such applications need to add custom code (using `shouldComponentUpdate`) to fix this scaling issue.

wasn't this done because e.g. updating manually a thousand elements one by one was shown to be, like, orders of magnitude slower than updating the whole thing ?
No, not at all.

On the one hand it is rare that you'd need to update a thousand elements at once one by one.

On the other hand, and more importantly, the problem that Virtual DOM aims to solve is not that one. Instead, what it wants to avoid is not "updating a thousand elements" but "replacing large sub-trees in the DOM unnecessarily".

That is, Virtual DOM competes, mostly, against doing something like...

    someElement.innerHTML = '...<a large piece of HTML>...'
The main concern of doing this is not so much that the performance is bad or not, but that it is intrinsically wasteful. That is, it [almost always] unnecessarily forces the browser to rebuild a part of the DOM and re-render a part of the page... just to change but a few values.

This is written in that way because it's easy to write it like that. But, being such a wasteful approach, it does end causing performance concerns.

Going from this, you can use various approaches. A Virtual DOM basically let's you manage your [virtual] DOM fragments as you were already doing but then inserts itself as a middleman to avoid doing those unnecessary DOM replacements and only modify what needs to be modified.

There are two things you need to notice here: First it does add some additional processing an calculation -"the diff"-. Second it still, because there is no other way to do it, uses the same DOM API calls you would use if "manually updating things".

So now you can balance this to see if it's worth it: On the one hand there's a cost -the added calculations-, on the other hand there is a gain -modifying only smaller parts of the DOM-. But be aware that this gain is compared not against "updating many elements" but against "rebuilding parts of the DOM when you don't need to". The distinction is rather important because if, suppose, you actually need to update the content of say a thousand <td>s in a table, your virtual DOM library will still need to do exactly that, it will do so by using the DOM API -because there's no other way-, and any additional processing it does will be added on top of doing that.

So... bad option: build a whole...

    <table><tr><td>A</td><td>B</td></tr><tr><td>C</td><td>D</td></tr>...</table>
...every time and dump it all into the DOM element; let the browser do all the work and live with the bad performance you get from having easy to write but wasteful code.

Virtual DOM solution: Still write easy to write and wasteful code but apply something in between that reads your "whole block" and finds what actually needs to be done and then does only that.

But it's not the only solution. Another solution is to just don't write that wasteful code in the first place. Instead of building large but mostly unchanged blocks and dump them, only modify what needs to be modified. Of course, it usually means that your code has to keep track of an additional bunch of things -i.e. where in the DOM does each piece of information go-, but this is where those other alternatives mentioned, like Svelte or others, may come into play.

The conclusion from all this is that:

a. No, a virtual DOM is not inherently faster than doing updates manually

b. A virtual DOM provides some gain by not doing unneeded updates of DOM branches. If you were doing those, using a virtual DOM may speed things up.

c. A virtual DOM still needs to do the DOM modifications with exactly the same API you would/could use manually so there's no gain there.

> On the one hand it is rare that you'd need to update a thousand elements at once one by one.

Is it ? I come from the desktop app world and that would frankly barely register above "toy project" ; my experience is more around a few tens / hundred of thousands objects that can change at once (with of course the UI framework only redrawing what needs redrawing).

> There are two things you need to notice here: First it does add some additional processing an calculation -"the diff"-. Second it still, because there is no other way to do it, uses the same DOM API calls you would use if "manually updating things".

I have a hard time understanding how, say, calling 500 methods per second on a DOM object, e.g. `label.innerText = someSensorValueComingFromWebsocketsVeryFast;`, which needs to trigger various events, callbacks, etc... every time could possibly be faster than modifying a pure JS object at the "incoming message rate" and then blitting that object at the screen refresh rate or something similar ?

> I have a hard time understanding how, say, calling 500 methods per second on a DOM object, e.g. `label.innerText = someSensorValueComingFromWebsocketsVeryFast;`, which needs to trigger various events, callbacks, etc... every time could possibly be faster than modifying a pure JS object at the "incoming message rate" and then blitting that object at the screen refresh rate or something similar ?

Updating a value on the DOM 500 times per second just because you can read it 500 times per second falls, again, in the category of writing wasteful code just because it's simpler. i.e. "don't care about performance, just let the browser work".

If you compare code which is initially bad, then sure, a lot of "solutions" will be better than that.

The appropriate comparison for evaluating the value of using a virtual DOM should not be about that, but only about the part you describe as "blitting the object to the screen". You have the data, no matter how, where, or even -to some extent- how often, and you want to put it on the screen.

> That is, it [almost always] unnecessarily forces the browser to rebuild a part of the DOM and re-render a part of the page... just to change but a few values.

That's a mere implementation detail. In practice, letting the browser re-render a single page chunk using its internal implementation will almost always be faster than using JS code to serially update any number of DOM elements. VDOM diffing is a kludge to make DOM manipulation in pure JS usable, it's not actually going to be faster than relying on the browser's own rendering. The biggest problem with the innerHTML is going to be generating the actual HTML, but one can most likely use WASM to speed that up.

Every time I see d3 stuff, it's pretty fast.
I don't think so. I believe it's because without a virtual DOM and a diff, how would react do rendering at all? The whole point of react is you just have a functional "render" method, so you need to render _somewhere_ (and it can't be the DOM for a variety of reasons, eg. deleting and rebuilding the whole DOM would be slow and break things like focus).

Svelte is different and doesn't export a render function -- the component knows what DOM nodes need to change for a given prop/reactive var change, so it doesn't need a virtual DOM (and can be much faster as a result)

"I hate people advocating for a tool by bringing up the problem it was used to solve. Just keep your app so simple that you don't need the tool."

A better solution is to emulate the react strategy. Create a state object, on user input you can rewrite sections DOM based on the state. You probably don't need React's diffing algorithm until you run into performance problems. Then you have to limit which parts of the Dom you update to keep it snappy. Then you might as well just use react.

> "I hate people advocating for a tool by bringing up the problem it was used to solve. Just keep your app so simple that you don't need the tool."

Casually dismissing others by strawmanning them with fake quotes is against the rules. Even outside of that, it's just generally the kind of thing that is neither respectful or respectable. Please don't do it.

It's not a fake quote. It's a statement of what I perceive his statement to mean. A translation.

Did you actually think I was trying to attribute that quote to op?

Then you end up rewriting a buggy under-performing version of React. No, thanks. If size is really a concern use Preact.
The beautiful thing about React is not React itself, but rather how much it pushed functional idioms into mainstream programming.

We can do better from here, mostly by hewing more to the functional core/imperative shell idea. Redux is a popular approach that shows the power of this. In more modern languages with ADTs you don’t even need a library/framework once you fully understand how to structure things well.

And me thinking .NET did it first with Rx.
Rx never got the attention it deserved IMO. It was the right thing but never really had the ergonomics.

It’s entirely possible I wasn’t able to appreciate it at the time, too.

It is part of Angular and everywhere on Android and iOS, it is plenty of attention.
And so you just recreate React but worse and make it harder to onboard new developers and can't use any of the great React libraries/components already created by the community.
It's all about scaling of complexity and number of engineers working on the project. No doubt hand rolled js is better when you only have to do the one thing you mentioned and you're the only person who has to read or write the code.

What happens when it's one of hundreds of checkboxes on the site? When they all do slightly different things depending on user sku, product page, file type, file permissions, god knows what else. And when one experiment flag is on or how about this other one? Then i18n? Then what about the fact that after you write this line countless other engineers will see and modify it in the future, it's not just you writing and maintaining it? These are the problems that my company (and, I assume, Publicis Sapient with 20,000 employees according to Google) have to consider when choosing whether to hand roll JS or use a framework.

Everything a programmer does is "hand rolled" whether it's JS or JSX.

You'll still have to tackle those complex requirements and come up with a good design that organizes things and makes them manageable, whether you're using React and JS or just JS.

To say that a good design is just impossible with JS or that no other engineers could possibly understand the resulting code seems absurd.

Javascript is a Turing-complete language. It gives you a lot of design options. Your poor engineers will have to learn it to use React anyway so why would vanilla js necessarily be worse than js plus a giant framework?

I once worked at a place that thought like the grandparent comment. "We're gonna have a huge app with lots of different UI variations. Let's use React. Then it will be super maintainable and scalable!" And then it turned out that if your plan to write maintainable code starts and ends at "use React", you will end up writing code that is not maintainable, and your framework will not save you, and in fact you will be fighting framework-induced bugs and performance issues on top of the problems caused by your total inability to design computer programs. The pace of software development at your company will grind to a halt, you will accept this as the only possible state of affairs (we're following all the best practices by using React!), and your company will limp along for a while and then go out of business.
It's more about the programmers than the underlying technology. But with react (and redux etc) very smart and experienced people have already put some thought into things like maintainability, and your chances of achieving success from the shoulders of these giants are higher than by starting from scratch.

Unless you don't need to reach that high.

I don't think that's really true. React doesn't give you less problems, it just gives you different problems that aren't as immediately visible because you haven't learned to look for them yet. For example, if you're used to thinking that every page of a web app can be tested individually, you won't notice bugs in single-page apps that only happen when using specific links to arrive on pages in a specific order.
React only gives you tools to reduce your problems.

In the case of single page apps, preventing you from shooting yourself in the foot is outside its scope.

What you are describing sounds more like a general problem in state management, and you'll have that with any framework. A common way to avoid such things in React applications is with Redux.

Unfortunately, even those advanced tools need to be learned and applied.

Building a doctor's appointment website with a form and a calendar widget? Use vanilla JS or jQuery.

Buidling the next Google Docs or Notion app? Use React/Angular, etc.

99% of the people that use React use it to build the former and then debate endlessly about their little teets and toots of JSX, Redux, Router library, etc. FFS, it is overkill and unnecessary. Simplify, go home on time and enjoy your the time with your family.

> Buidling the next Google Docs or Notion app? Use React/Angular, etc.

Wouldn't the performance of Google Docs suffer too much by using React? If I remember correctly they're switching to canvas-based rendering. Same thing with VSCode, they don't use a framework. I'm not sure about Notion, as I don't use it much, but I've never been impressed by the performance too. I think your best bet for React/Angular is around "medium complexity", so a typical web app that isn't that complex.

This is a content-free take. Swap in any methodology or design technique ("functions", "structured programming", "Unix pipes", "any higher-level programming language than raw assembly"...) and it would be just as meaningful. These are abstractions that help produce a good design to organize things and make them manageable.
React is quite a minimal framework (or not even a framework), actually. It's just that it has a huge following and takes some mind-bending to actually benefit from it.
Last time I checked, React itself was 150kb minified. OK for a 2mb page. Not ok for 20kb pages.
I'm not in the business of building 20kb pages.

Working with any significant backend API, loading any images, or even your own javascript functionality takes you over that limit easily.

And then there is caching and CDNs...

Why not? At that size, it takes less than your client can blink to load it.
If your client is an otherwise idle system with the latest browser, a fast wired connection, and the developers carefully monitor time to render.

In most cases, at least one of those is not true and the developers are using something like CRA so your site has a number of users who see tens of seconds of nothing while their Android phone downloads and runs a 1MB JS bundle. Bonus points if the marketing department has tossed in a tag manager which delays that even longer.

What you consider minimal, some consider a 100-lb gorilla.
> What you consider minimal, some consider a 100-lb gorilla

A 100-lb gorilla is...quite minimal, actually.

> Male gorillas of the Western lowland gorilla (Gorilla gorilla gorilla) subspecies have average weight up to 140 kg (310 pounds) while females have up to 90 kg (200 pounds).

https://gorillafacts.org/how-much-does-a-gorilla-weigh/

That's about the weight of a chimp.
I think in metric system :D
Then you can switch to something like React. But most projects won't ever get close to the level of complexity you are describing.

Meanwhile I have seen SO MANY sites that use full React for a contact form with two fields on it.

You don't need to get close to that level of complexity for React to become useful.

> Meanwhile I have seen SO MANY sites that use full React for a contact form with two fields on it.

I agree that the contact form you describe would be dead-easy to do vanilla. Maybe throw in Parcel if you want to write ES6.

However, while I suspect some people may use React in this case because it's all they know, others may do it because they are literally faster in React - they have a workflow that can see them code and deploy such a website to Netlify or Heroku or whatever in 10 minutes.

Preact to render the view and a dozen lines to handle the submission and data in a closure are still likely an easier solution than vanilla JS.
Which is fine if your company and teams use React a lot.

Why introduce inconsistency in everyone's workflow just because this specific page is a simple contact form?

The fact that it is just a simple contact form is exactly why you should use the same tools and workflow that everyone in your team has already been using.

Write what other people knows so you don't have to be the one maintaining it.

Yup. React is a tool so that thousands of people can speak the same language about a big codebase. That's what it's for, that's the only thing it's (arguably) good at. If you want to pretend otherwise you're left to these sorts of mental gymnastics to make the evidence fit your assumptions.
How does it achieve this?/aim to achieve this?
You (and most commenters on this branch) forget the most important thing: there are bazillions of libraries that work with react so I don't have to produce all that untested vanilla code. I only have to wire them together in a way I see fit and then I can jump on the next project. Also: good luck finding a person who would forego using and maintaining their easy-to-market React skills.
None of which is specific to React, as decades of history shows. One reason that history is worth paying attention to is that it confirms that you’ll be spending a lot of time managing dependencies, testing breaking upgrades, and working with upstream maintainers to fix problems and add features. It’s still a net win but there’s a real cost which is easy to ignore until you count the number of FTE weeks which went into keeping a project building and secure.
The example as shown doesn’t even need JavaScript. It could be a few lines of css.
And that would be even shorter than the React version.
You're right that this doesn't represent the way a vanilla JS UI would ever actually be written in practice (even calling it a "vanilla JS UI" instead of an "html UI" points directly at the problem)

But:

1) Even though the web-specific example is contrived, it's a good demonstration/explanation of what people mean generally by declarative vs imperative

2) I don't want to wade into the tired argument, but classic HTML + minimal hand-written JS doesn't scale beyond a certain point. If it did, everyone would still be doing things that way

If you need to achieve the same functionality and maintainability without React (or some other external library), then by definition you somehow have to reimplement much of it yourself. And no, React isn't all that big in terms of functionality or size.

What are the chances that you are arriving at a solution that is better than React? That other engineers have no trouble understanding and maintaining? You'd have to invent new concepts, or at least call them differently, to not copy React's (or any other framerwork's) concepts or ideas. That would make it harder for other people to understand the code.

For primitive apps or anything that’s very straightforward like CRUD forms and tables, vanilla works great and should be encouraged.

Anything moderately complex gets really painful when you’re storing state in all your HTML elements.

A big part of React is to abstract away the horribleness of trying to prevent unnecessary, quite expensive interactions with the DOM.

That’s why a lot of comparison examples miss the point and facilitate poor discussion.