跪拜 Guibai
← All articles
Vue.js · React.js · Vapor

Vue 3.6 Vapor Mode and React 19 Compiler Are Two Opposite Bets on Killing Wasted Re-renders

By GitLqr ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

The two most widely adopted frontend frameworks are now shipping fundamentally incompatible solutions to the same performance problem. Choosing one path over the other locks a team into a specific architecture, migration cost, and debugging model for years.

Summary

Frontend performance optimization has split into two incompatible strategies for eliminating wasted re-renders. Vue 3.6's Vapor Mode adopts a Signals-based, fine-grained reactivity model that compiles templates into precise DOM mutations, treating the component function as a one-time setup routine rather than a re-running render function. React 19's compiler takes the opposite approach: it preserves the Virtual DOM and the snapshot mental model, but uses compile-time AST analysis to automatically insert the useMemo and useCallback caching that developers previously wrote by hand.

The divergence is architectural, not superficial. Signals decouple state from the component lifecycle, enabling push-pull hybrid updates that avoid re-executing entire component trees. React explicitly rejected this path because mutable, subscribable references conflict with concurrent rendering and risk creating untraceable data flow in large codebases. The React team's bet is that zero-migration compiler optimizations, combined with strict adherence to the Rules of React, deliver enough performance without fracturing the declarative programming model.

For teams choosing between them, the trade-offs are concrete. Signals-based frameworks excel in high-frequency update scenarios like dashboards and collaboration tools, where redundant JavaScript execution directly starves the main thread. React Compiler suits large legacy projects and teams that prioritize developer experience and predictable data flow over absolute rendering precision.

Takeaways
Vue 3.6 Vapor Mode compiles templates directly to DOM operations, skipping the Virtual DOM entirely.
React 19's stable compiler automates memoization at build time by analyzing the component's AST and inserting cache checks.
In a Signals-based model, the component function runs once as a setup routine; only the specific DOM nodes subscribed to a changed value update.
Modern Signals use a push-pull hybrid: a dirty flag propagates through the dependency graph, but computation stays lazy until the value is actually read.
React rejected Signals because mutable, subscribable references break the snapshot model and risk tearing during concurrent rendering.
React Compiler requires strict adherence to the Rules of React; components that violate them are silently skipped by the optimizer.
Signals frameworks suit high-frequency update scenarios like real-time dashboards and collaboration tools; React Compiler suits large legacy projects with zero migration cost.
Conclusions

React's refusal to adopt Signals is not about performance ignorance but about preserving a programming model where UI is a pure function of state at a single point in time. That constraint makes concurrent features like selective hydration and time-slicing possible.

The push-pull hybrid in modern Signals is an underappreciated engineering detail. It avoids the glitches that plagued earlier Observable libraries by marking dependencies dirty without eagerly recomputing them, which keeps the main thread free for other work.

React Compiler's silent bail-out on non-conforming components creates a hidden performance cliff: a team might believe the compiler has optimized their app when in fact large portions were skipped because of subtle rule violations.

The manual memoization era ending means a whole class of React performance bugs—stale closures, missing dependency arrays, over-memoization—disappears, but only for codebases that can pass the compiler's static analysis.

Concepts & terms
Vapor Mode
A Vue 3.6 compilation strategy that bypasses the Virtual DOM and generates direct DOM manipulation instructions from templates, using fine-grained reactivity to update only the nodes bound to changed state.
Signals
Reactive primitives that track which specific DOM nodes or computations depend on them. When a Signal's value changes, it pushes a dirty notification through the dependency graph, and the actual recomputation happens lazily only when the value is read.
Push-Pull Hybrid
A reactivity scheduling mechanism where state changes push a dirty flag to subscribers, but the actual computation is pulled lazily on access. This avoids redundant intermediate calculations and the glitches common in pure-push Observable patterns.
React Compiler
A build-time tool introduced in React 19 that statically analyzes component ASTs to automatically insert memoization (useMemo, useCallback) and cache slots, eliminating the need for manual performance optimization while preserving the Virtual DOM model.
Concurrent Rendering
React's ability to pause, prioritize, and restart rendering work. It depends on the assumption that UI is a pure snapshot of state; direct DOM mutations from Signals mid-render would cause tearing, where different screen regions display inconsistent state versions.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗