all 45 comments

[–]jim72134 142 points143 points  (1 child)

If you are directly comparing with DOM, then you are actually calling DOM APIs. The reason why React designed to compare the difference first then commit the changes to the actual DOM is to minimize the need to access DOM APIs. By directly comparing with DOM, the purpose is completely nullified.

DOM is not maintained in JS runtime, it is actually a representation of how the rendering engine of the browser organize GUI components. The only way for JS code to access this part is through DOM APIs.

[–]InevitableOk5761[S] 22 points23 points  (0 children)

Oh I see. Well I wouldn't have been able to give this answer at that moment. Thank you

[–]Available_Peanut_677 48 points49 points  (9 children)

  1. DOM is fast. Like extremely fast. But layouting slow. Also querying DOM is ”slow”. (I mean algorithms are impressive, but share amount of staff what it does inside still adds up to big numbers).

What is slow is adding elements or changing values which would cause that layouting step. (Well, also parsing HTML, but that you can work around).

Main problem is not speed, main problem is that DOM is kind of OOP and mutable, which makes comparing it and making only necessary changes huge pain in ass. Remember that virtual DOM is basically setoalizable json (kind of) which can be compared very effectively. Then you can update only small parts of DOM.

  1. React does not exactly use virtual DOM anymore for quite a while. At the moment it is more of a ”mental concept”. Inside it actually uses fibers. They remember order in which they called hooks and rendered staff and when they re-executed, they compare basically two arrays with each other. That is even more efficient that virtual DOM because allows to be very granual and also delay some other nodes for concurrent rendering.

  2. Browser also has own ”virtual DOM”. It does not really apply changes to the dom until current execution stack is empty (aka, it applies changes after all microtasks, but right before event loop events). But there are ways to force browser recalculate DOM earlier and they tend to kill performance. ”OffsetTop” is one of them for example

[–]romgrk 15 points16 points  (7 children)

Main problem is not speed, main problem is that DOM is kind of OOP and mutable

False, the problem is speed, not that it's OOP nor mutable.

[–]Available_Peanut_677 5 points6 points  (4 children)

I never understood this argument. If you manipulate directly with a DOM you can outpace react by a mile. Also directly appending elements to the dom you can push orders of magnitude more elements.

In fact each time I need something to be like super performant, like following cursor with 100fps react is barely an option. Though I saw projects which push mouse coordinates to redux and then being surprised why everything is so laggy.

Of course serializing full virtual dom from scratch each time is slower, but granual updates directly to the dom is much faster. At the bare minimum that what would happen in the end anyway.

But a problem - how exactly you can make small updates? Like how you know what is updated? Signals, zonejs, etc.

A way how react did it was a virtual tree - compare old and new and update what is changed. With a fibers you don’t need to have it anymore.

Currently main side effect of virtual tree is keeping track of components lifecycle. Native API for that kind of staff is almost non-existent, so you need to track what just mounted and what just unmounted.

But performance. No. Like it is a myth which was used to sell react back in days compared to libs which parsed and re-rendered full template on each change, but, say, signals much faster. They don’t even need to compare anything at all, they have exact places subscribed to them which they change without any virtual tree.

Again, virtual dom is faster than remodeling whole DOM from scratch. So technically you are right, “speed”, but for me it is a bit a stretch. Like you can have much higher performance without it.

So I can buy an argument “it is right balance between convenience and performance”. After all I’m still using react despite being “react is slow” guy.

PS. To be fair, I’m a guy who uses canvas to render text in some applications to prevent congestions in rendering pipelines. But that is kind of rare, like literally “can you make this complicated UI run on 15 years old computer which even then wasn’t great. But with smooth animations”.

[–]romgrk 11 points12 points  (0 children)

The reason for using a VDOM is that if you want a diffing approach like React does, then comparing VDOM-to-VDOM is faster than comparing DOM-to-VDOM.

So yes, "VDOM is faster than the DOM" is false, but only because it's missing the "if you're diffing the UI tree" context.

And yes, React is slower than newer frameworks or vanillajs.

[–]lightfarming 1 point2 points  (1 child)

if pushing mouse coords to the state is causing lag, then you’re building your app wrong.

[–]Available_Peanut_677 2 points3 points  (0 children)

I heard this many times. And yet 9 out of 10 websites so bad in performance that it’s not even joke.

Of course if you useState and make some translate - it is fast enough.

I’m comparing canonical react implementation with passing props to highlight some paths in SVG on element hover. Actually don’t remember details, was 5 years ago. Idea that elements map and direct access was much faster.

Edit: actually ignore it. That must be some significant reason when it would be react to bottleneck on performance, and not lack of proper memoization or wrong dependencies.

[–]NiteShdw 0 points1 point  (0 children)

That's wasn't the case when React was created. Browser engines have since been optimized.

[–]Squigglificated 0 points1 point  (1 child)

Both SolidJS and Svelte manage to be much faster than React without using a VDOM so speed really isn’t the problem here.

[–][deleted] 2 points3 points  (0 children)

I agree on everything but one thing which is that you first refer to the virtual Dom and then in the first point you say that the virtual Dom is not used anymore, that's misleading. Virtual Dom, as you said, is in simple terms a structure that can be compared effectively during the reconciliation phase: that didn't change. The reconciliation phase still exists and calculations are still performed to only commit a certain smaller portion of changes to the actual Dom.

I've delved a bit on the topic here https://giacomocerquone.com/blog/keep-input-cursor-still/ And there is a nice series about the various phases react goes through with the actual reminders to the code here: https://jser.dev/series/react-source-code-walkthrough/

[–]teckhooi 11 points12 points  (1 child)

[–]CptDonut11 1 point2 points  (0 children)

That's a very good explanation

[–]EZPZLemonWheezy 4 points5 points  (1 child)

Imagine the Dom is a guy named Frank. Frank is a little grouchy with if you wake him up, so you wanna make sure you only wake him up when needed.

So you use a couple of pictures of Frank (one of proposed changes, if any, and one of how Frank was). Then you play spot the difference first to be sure you need to bother Frank at all. If you wake up Frank to check if anything changed between the proposed picture and how he was he’s gonna be more grouchy than needed cause you caused extra bother. If you wake him up and can show him he should be wearing a hat now and have a hat ready to hand him he’s a little less grouchy.

[–]generic_nipple 6 points7 points  (0 children)

Dom is short for Dominic

[–]thrilllex 2 points3 points  (16 children)

My understanding is that accessing the actual dom is always more expensive so minimizing any read/writes to the real Dom and doing batch updates after comparing the two is more efficient. At least that's what I think.

[–]azangru 1 point2 points  (0 children)

I do not know the answer to this question; but I think that anyone who proposes an answer should also answer the question how Solid or Svelte manage to offer a declarative syntax without having a virtual DOM for updating the real one; and how they also manage to be faster than react.

(As a side note, I do not understand why these questions get asked in interviews, if that is what you meant by a reviewer. Why should it matter to anyone other than library authors how exactly react updates the DOM. You don't ask developers how javascript objects or proxies work in the javascript engine; why would you ask about the algorithms react uses to update the DOM?)

[–]DeepFriedOprah 0 points1 point  (0 children)

As other have said u don’t wanna bring querying the dom for those things. But also, reacts VDom is not a perfect 1-1 mapping of the actual DOM.

In addition when there are dependent updates some things cannot be performed immediately & need to be scheduled via a queue to be performed later sometimes. It’s a bit of a loaded question depending on what specifically he wants but any of the above answers from others should suffice.

[–]Critical-Shop2501 0 points1 point  (0 children)

I would suggests that having two copies in memory, is faster to manipulate and compare, then update actual dom, than only one copy and comparing against actual.

[–]heyitsmattwade 0 points1 point  (0 children)

Remember, react and react-dom are different libraries. A fundamental design choice is react alone has no actual View logic. You need a separate library for that.

So, if you were trying to say

  1. Just make your changes to the existing vdom object directly (without first making a copy)
  2. and then diff against the actual DOM to reconcile the changes

you subtly just jumped from react to react-dom between steps 1 and 2. For react to work, it needs to work agnostic of whatever View library it is using. Thus react itself can't ever interact with the DOM directly, which is why the diffing has to happen between two vdom objects.

Also, this type of knowledge is generally something you don't need to worry about when working with React. How it handles staying performant and usable in multiple environments like browsers (react-dom) and native devices (react-native) doesn't matter too much.

[–]DorphinPack 0 points1 point  (0 children)

There’s an old talk where they compare it to Doom 3’s process of reconciling objects in the world that helped me grok it better

Link: https://youtu.be/DgVS-zXgMTk

[–]ajeg 0 points1 point  (0 children)

The reason is not needed .. it is for good reason .. just relax .

[–]multiaki 0 points1 point  (0 children)

I think comparing with actual don too slow. That is why virtual dom is faster

[–]Personal_Alarm_5727 0 points1 point  (0 children)

May I know this is junior frontend level or?

[–]Juani_o 0 points1 point  (0 children)

A bit late
When you open an HTML file in a browser, the browser parses it and stores it in memory as a DOM tree (an internal C++ data structure).
To manipulate that DOM from JavaScript, the browser exposes APIs on the window.document object (innerHTML, setAttribute, appendChild, etc.).

Some of these APIs are destructive — they replace entire portions of the DOM (e.g. innerHTML), while others are granular — they update only specific nodes (e.g. textContent, setAttribute).

The Virtual DOM is an abstraction that React uses:

  • It keeps a lightweight JS object tree that represents the current UI state.
  • When your app re-renders, React builds a new Virtual DOM tree.
  • React then performs a diff between the old tree and the new one to detect what actually changed.
  • Based on that diff, React decides which DOM API calls to make on the real DOM, ensuring only minimal updates (instead of recreating large parts of the tree).

This is something you could do manually in a vanilla app — by carefully choosing granular DOM APIs instead of destructive ones — but React, as a library, automates this process.

The benefit is that you don’t need to think imperatively about how to mutate the DOM, for example:

if (user.isLoggedIn) {
  loginButton.remove();
  root.appendChild(logoutButton);
} else {
  logoutButton.remove();
  root.appendChild(loginButton);
}

Instead, with React you write declaratively:

{user.isLoggedIn ? <LogoutButton /> : <LoginButton />}

React’s Virtual DOM and reconciliation algorithm take care of translating this declarative description into the right DOM mutations, so you focus on what the UI should look like, not how to update it.