Sowohl React als auch Vue sind vom Konzept her deklarativ, was ja erstmal nicht schlecht ist. Leider hat das zur Folge, dass prinzipiell nicht vorgesehen ist, am bestehenden DOM der Seite Veränderungen vorzunehmen. Was React oder Vue vom Entwickler erwarten, ist die Bereitstellung von Templates für Komponenten. Daraus wird dann ein virtuelles DOM erzeugt, also im Wesentlichen eine Abstraktion des realen DOM, aus dem dann unter der Haube die richtige DOM–Repräsentation der Komponente generiert wird. Das heißt, es werden in jedem Fall neue Elemente erzeugt und der Seite hinzugefügt, selbst dann, wenn es einen Fallback für die Komponente gibt, dessen DOM hätte wiederverwendet werden können. Ein solcher wird dann üblicherweise wieder aus dem DOM entfernt und an dessen Stelle die neuen Elemente eingefügt. Die Folgen sind Reflow und Repaint.
Das ist nicht ganz richtig. Zum Virtual DOM gehört in der Regel auch ein Diffing-Algorithmus, der merkt sich welche Knoten im DOM vorhanden sind und berechnet bei einem Update eine möglichst kleine Menge an Änderungen, die im DOM vorgenommen werden müsen, um den neuen Zustand auf den Bildschirm zu bringen. Diese Menge an Änderungen wird dann dem Framework-Renderer übergeben, der optimiert dann noch weiter, zum Beispiel werden Änderungen, die einen Reflow- oder Repaint auslösen gebatcht, also in einer einzigen DOM-Operation anstelle mehrerer abgearbeitet. Meiner Erfahrung nach ist der zusätzliche Overhead das meistens wert, zumindest wenn man in hinreichend komplexen, dynamischen Web-Anwendungen arbeitet. Das fällt schwer zu glauben und außer aus meiner eigenen Erfahrung kann ich da wenig belastbares Material zu liefern, außer vielleicht dieser Todo MVC Benchmark, da ist Vue sogar schneller als Vanilla.js.
Ein Problemfall ist der erste Framwork-Rendering-Vorgang, den hattest du vermutlich auch beim Schreiben im Hinterkopf. Da gibt es zwei Fälle zu unterscheiden, jenachdem ob der Server schon das statische HTML für den initialen Anwendungszustand geliefert hat oder nicht. Im zweiten Fall ist man verloren, denn da muss das Framework den kompletten Rendering-Vorgang selbst übernehmen, da gibt es noch nichts zu diffen, alles muss vom Framework in das DOM eingefügt werden. Das ist leider bei vielen SPAs so. Im ersten Fall kann man aber was machen. Vue.js zum Beispiel kann das statische HTML weiterbenutzen und wie oben beschrieben sofort den Diffing-Algorithmus einsetzen, um nur minimale Änderungen vorzunehmen. Das nennt sich in Vue.js Client Side Hydration. Das geht aber auch nicht ohne zusätzliche Vorkehrungen, das statische HTML muss Vue.js diverse Zusatzinformationen mitliefern, damit Vue.js sich richtig initialisiert. Das muss man nicht zu Fuß machen, für Vue gibt es Pakete um serverseitig entsprechendes Markup zu rendern, und man kann dafür die clientseitigen Templates auch wiederbenutzen. Das bringt sogar noch ein paar Goodies mit, zum Beispiel kann kritisches CSS von Vue direkt geinlined werden, um das Laden noch schneller zu machen.