In order for React to know though when to re-render and when not it uses a diff technique where it compares the old version of the DOM (before the change) with the new version of the DOM (after the change) and if a change is detected then it calls for a re-render. This process is called reconciliation.
The above sounds like a very suboptimal solution. Re-rendering everything on a simple change would normally be a O(n^3) problem, where n is the number of nodes. So for a page with 1000 nodes we would have to do 1 BILLION comparisons, which would have taken us 1 second with modern CPUs but it’s still unacceptably slow. React engineers managed to make this problem an O(n) complexity problem by accepting 2 simple heuristics: Two components of the same class will generate similar trees and two components of different classes will generate different trees.
It is possible to provide a unique key for elements that is stable across different renders. So if you use the virtual DOM and the above heuristics you end up with an algorithm in which you are comparing 2 arrays (the old Virtual DOM vs the new Virtual DOM). If the new DOM is from a different class React will render it, no questions asked, if it’s from the same class react will compare the individual attributes between the old and the new version. The result is that only changed components are being rendered and the entire operation is cheaper and faster. There are some more side benefits too.
Clever as it sounds, using fancy heuristics and tree traversal and all that, we can further improve the performance of React by adding Immutable data in our lives. With Immutable data, every time we change something in a data structure a new version of it is being created. What this means is, that if the virtual DOM is in a structure that can’t be mutated, every time a change is happening we’ll have a new state in which the component will be pointing at. This enables us to skip checking the component attributes all together and move on to the next. This is happening because we know that since our data is Immutable we can’t possibly have a change in the component if we’re still using the same virtual DOM. This little functional programming paradigm helps making the reconciliation process from an O(n) problem to a O(log(n)) problem, and this is a massive improvement.
On the negative side of things, using immutable data makes pushing in the virtual DOM array slower by 3 to 5 times, but this is a constant number and the benefits from getting from an O(n) to a O(log(n)) outweigh that constant penalty in push. If you want to learn more about React and immutable data I highly recommend watching this video from ReactConf 2015.
There are a few frameworks that plug on top of React to give you the power of immutable data, one is OM and the other Immutable-JS. It’s really worth checking them out.