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 ?
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.
...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.
> 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.
But the solution to the problem which is
how to go from
inputs (which you don't have any control over)
to
"You have the data, no matter how, where, or even -to some extent- how often, and you want to put it on the screen"
Maybe you can find some rendering comparisons from a few years ago. There was some "demo" called DBMonster or DBMON that showed the performance of updating a large amount of values on a table in a web page. The thing is a lot of different implementations were then written by many people using many different frameworks -including many using a virtual DOM and many not using one- and also even some "vanilla" implementations. I don't suggest it for the performance comparison -which you can of course look into- but, more in line with the question: it may be a good way to find a number of different approaches.
> 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.
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)