20

I understand that React creates a virtual DOM and compares the difference and then just updated the actual element of the real DOM but how is that more efficient if I change it manually? Via getElementById or by using the jQuery function?

<!DOCTYPE html>
<html>
<body>

<form>
Select your favorite browser:
<select id="myList" onchange="myFunction()">
  <option></option>
  <option>Google Chrome</option>
  <option>Firefox</option>  
  <option>Internet Explorer</option>
  <option>Safari</option>
  <option>Opera</option>
</select>
<p>Your favorite browser is: <input type="text" id="demo" size="20"></p>
</form>

<script>
function myFunction() {
    var mylist = document.getElementById("myList");
    document.getElementById("demo").value = mylist.options[mylist.selectedIndex].text;
}
</script>

</body>
</html>
Gaurav Paliwal
  • 1,556
  • 16
  • 27
Yahoo
  • 4,093
  • 17
  • 59
  • 85

1 Answers1

36

Changing Virtual DOM should not be much different than changing the real DOM. The problem is in the aftermath: changes in real DOM trigger relayout and repaint, so the less we touch the real thing, the better.

One way to do template rendering is to render the template, then replace the whole container element with newly rendered template. This needs to recalculate everything that just appeared within the container, and everything affected by it. Basically, if the browser was your kitchen and your template container a fridge (and your image of the fridge as it would be in five minutes, your virtual DOM), and you bought a lemon, typical template render would throw out your fridge, imagine what the fridge with a lemon would look like, buy all the ingredients you had before and also a lemon, then fill the new fridge.

The thing that React and other similar frameworks do that speeds this up is the diff process, that finds the minimal set of changes to get the real DOM to reflect the virtual DOM, which can drastically reduce the number of recalculations the browser will need to do in order to paint it. In the previous analogy, you imagine what your fridge would be like after you bought a lemon (fridge with no lemon vs fridge with a lemon), figure out the minimal change (add the lemon) and perform it.

It so happens that throwing out a fridge every time you change anything in it is kind of expensive.

Note that Virtual DOM is not quicker than simply fetching one element via getElementById and changing it. The comparison is between two ways of dealing with changes in complex subtrees, not single elements.

Amadan
  • 191,408
  • 23
  • 240
  • 301
  • 4
    I guess I am not understanding `The comparison is between two ways of dealing with changes in complex subtrees, not single elements.`. and hence the confusion. Can you give an example of complex subtrees? – Yahoo Jul 20 '18 at 05:21
  • 1
    In React terms, a component. Given that in React components can (and almost always are) nested, and that you can (and often do) have a main component that basically renders your whole site... that's a complex subtree. Imagine if Stack Overflow was a React app; the whole page would be a component (that consisted of top, leftnav, content, rightnav, footer). If a message comes, we need to add a badge to an element in the top. Rerendering the page to reflect the new badge would need to recalculate all the layout, answers, comments, job offers, everything. But with diff, can just change the badge. – Amadan Jul 20 '18 at 05:22
  • 5
    If I do a `document.getElementById("myList");` and then update it in that case also the ` re-layout and repaint` will happen on the browser and in case of React, it will also be updating the same component and in that case also the ` re-layout and repaint` for that component happen. So how is react being efficient? @Amadan – Yahoo Jul 20 '18 at 05:27
  • 9
    Again, it is _not_ efficient in comparison to manually changing one element. One-element component being changed is _more_ work than manually changing one element. It is efficient in changing a complex structure where a small part changes: e.g. a component that lists 100 items of which one item is changed (naive template, e.g. `container.innerHTML = newHTML`, changes all 100 items, diff algorithm only changes that one). – Amadan Jul 20 '18 at 05:29
  • 6
    Oh, so you mean that if for a list of 100 items, I either `a)` will have to manually know which item as changed then I can do the `getElementById`, but if I had to change 20 of those, then I had to write more code and know the ID of each 20 element or b) to save lines of code just delete the entire list and recreate a new one. This recreate will re-render 100 items, but if I use `react` then it will just update the 20 item and I don't have to worry about knowing the ids of those 20 elements (react will figure it out)? – Yahoo Jul 20 '18 at 05:35
  • 5
    That makes sense, but then why does browser`container.innerHTML = newHTML`, changes all 100 items? why doesn't it internally use this diff mechanism? (If they do then we would not have needed to react?) – Yahoo Jul 20 '18 at 05:38
  • 3
    Possibly because it is only less work when you are predictably changing small buts at a time. In case you want to replace an element’s content with another, figuring out the diff is actually *more* work, and browsers shouldn’t assume that. Whatever the reason, browsers don’t (and given that there are many frameworks doing it in slightly different ways, they probably shouldn’t). The base operation should be simple and predictable. – Amadan Jul 20 '18 at 05:43
  • Got it, Thanks for the help! :) @amadan – Yahoo Jul 20 '18 at 05:49