React is one of the most if not the most popular frontend UI frameworks developers use today. Someone new to the framework can get an application up and running in no time at all. React can be thought of as one big abstraction on top of standard JavaScript. That is to say, one can make the same application with plain JavaScript as they can with React; it just will be much harder.
One of the key React features is updating the DOM without having to write the code that updates the DOM manually. Let's review what the DOM is. DOM stands for Document Object Model, and it is a tree-like structure that the browser generates from the loaded HTML file. Updating the DOM manually is not difficult, but it is difficult to update based on data changes at scale. If a value changes in your code, what exactly about the DOM should change? If we change the entire DOM every time, critical user state can be lost and entire apps would be rerendered instead of the one piece that needs to be rerendered.
React solves this problem by using a virtual DOM. A virtual DOM is a representation of the DOM in browser memory, and it allows React to be able to compute minimal DOM operations when rerendering the UI. Whenever a change is made in the virtual DOM, a snapshot of the virtual DOM is compared to another taken right before the update. Whatever is determined to be changed will be updated in the actual DOM. This process of comparing previous to updated state is commonly called, "diffing."
The Diffing Alogrithm
Let's start with some example code.
<span className="fruit" id="fruit">My fruit: Apple</span>
=>
<span className="fruit" id="fruit">My fruit: Banana</span>
When diffing happens, React checks to see if the previous and updated snapshots have the same root element (<span>
). If that element has been unchanged, it will then check the attributes of the tag (className
and id
). If both are unchanged, React then moves on to the children and repeats the same process. In the above example, React would recognize that "My fruit: Apple" turned into "My fruit: Banana" and would then only update that text while keeping the parent <span>
tag in tact along with its attributes.
Diffing lists
Let's again start with some example code
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Cherry</li>
</ul>
Let's then add Date
to the end of the list.
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Cherry</li>
<li>Date</li>
</ul>
React sees that the <ul>
tag is unchanged so it then proceeds to check the individual <li>
tags. It sees that Apple
, Banana
, and Cherry
are all unchanged, and then it sees that Date has been added so React appends it to the end of the list. What if we inserted Apricot
after Apple
?
<ul>
<li>Apple</li>
<li>Apricot</li>
<li>Banana</li>
<li>Cherry</li>
<li>Date</li>
</ul>
React sees that the <ul>
tag is unchanged so it then proceeds to check the individual <li>
tags. It sees that Apple has been unchanged, but when it gets to the second <li>
tag, it sees that it is now Apricot
and not Banana
. Similarly, it sees that the third <li>
tag is not Cherry
but is now Banana
. This pattern repeats to the end of the list, and consequently everything within the list besides Apple
would be rerendered. This is obviously suboptimal. Everything stayed the same and shouldn't have been rerendered. We just need to clue React in to it. Luckily, React gives us that ability with the key
attribute.
<ul>
<li key="Apple">Apple</li>
<li key="Banana">Banana</li>
<li key="Cherry">Cherry</li>
</ul>
<ul>
<li key="Apple">Apple</li>
<li key="Apricot">Apricot</li>
<li key="Banana">Banana</li>
<li key="Cherry">Cherry</li>
<li key="Date">Date</li>
</ul>
With this implementation React knows that we have only inserted Apricot
and appended Date
and would then preserve the fruits that are unchanged without rerendering them.
Word to the wise: Never use indexes as your key values! This will lead to rerenders if you ever insert or prepend elements into your lists!
Conclusion
The virtual DOM is the strategy React employs to have minimal DOM operations. It's not as scary as the name might suggest! I hope that reading this has given you confidence to approach conversations around it and the insight to write better React code.