React NativeとReact DOMでVDOMの持ち方が違う気がするという話、調べてみたらやっぱりそうでした。
ReactDOMがReal DOMへの書き込みに使っているcommitUpdateという関数があります。 https://github.com/facebook/react/blob/3d8f465d99ece19238ccb561cdb157d2d676dda4/packages/react-dom/src/client/ReactDOM.js#L716
ReactDOMのほうは辿っていくとReal DOMのElementをゴリゴリ弄っている場所に辿り着けます https://github.com/facebook/react/blob/3d8f465d99ece19238ccb561cdb157d2d676dda4/packages/react-dom/src/client/DOMPropertyOperations.js#L116-L173
ReactDOMと同じくReact NativeのJS側のRendererにもほぼ同じAPIでcommitUpdateが実装されています。 https://github.com/facebook/react/blob/3d8f465d99ece19238ccb561cdb157d2d676dda4/packages/react-native-renderer/src/ReactNativeFiberRenderer.js#L263
余談ですがこいつもfacebook/reactプロジェクト内なんです
ただし、ReactDOMのそれとは異なり、辿っていっても https://github.com/facebook/react-native/blob/4f886a29a1234c967deae2354bbc5092e0e6595e/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java#L367-L376
ReactShadowNodeという「もう一つのVirtual DOM」を更新して https://github.com/facebook/react-native/blob/4f886a29a1234c967deae2354bbc5092e0e6595e/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java#L307-L322
なんでVDOMを二回も作っているのかというと、きっとスレッド周りの話と無関係ではないのだろうなと思います。
ReactDOMの場合はReactDOM自体がいわばUIスレッドで動いているので、いつElementを触りに行こうが勝手です。
一方で、React NativeはJSの実行スレッドとネイティブUIのスレッドが別々に走っています。何かしらの形で間を埋めなければなりません。
それを解決したのがキューイングだったのでしょう。JSのスレッドからは好きなタイミングでキューに更新指示を突っ込み、UIスレッドはそれを好きなタイミングで拾って更新すればいいのです。
ちょっと腑に落ちないのがReactShadowNodeの存在です。差分管理はReact側で済ませてあるはずなので、わざわざもう一度VDOMを作って管理する必要はないはずなのですが・・・
Yogaでスタイルを実装したVDOMレイヤーがひとつ欲しかったのかな・・・