How React, Angular, and Vue Detect Changes and Perform Batch Updates
This article examines how modern frontend frameworks—React, Angular 1, Angular 2, and Vue—detect data changes and implement batch updates, comparing their virtual DOM diffing, dirty checking, zone.js, and asynchronous queues to reveal each library’s underlying change‑detection strategy.
Introduction
In traditional web development, developers manually fetch data and update the DOM, which is error‑prone and hard to maintain for complex pages. Modern frameworks such as React, Angular, and Vue let developers focus on data, automatically updating the DOM when data changes. This article analyses how these frameworks detect data changes and perform batch updates.
React
Virtual DOM
React creates two virtual DOM trees from the old and new state, compares them with a diff algorithm, and updates only the changed parts of the real DOM. Data changes are signaled by calling
setState.
setState
Example component (image):
When the button calls
this.setState({val: 1}), React updates
this.state.valto 1 and re‑renders the UI. If
setStateis called multiple times in the same event handler, React batches the updates instead of applying them synchronously.
Testing with three scenarios—events, timers, and XHR—shows that calls made inside React’s own event handlers are batched, while those triggered from asynchronous callbacks are applied immediately.
In React‑invoked methods, consecutive setState calls are batched; otherwise they are applied immediately.
Thus, React’s batch update relies on the execution context of the call.
Transaction
React uses a transaction system to wrap functions, invoking
initializebefore execution and
closeafter, enabling batch updates.
The core
setStateimplementation checks
batchingStrategy.isBatchingUpdatesto decide between
batchedUpdatesand
dirtyComponents.push, as illustrated in the diagram.
Summary: React detects changes via
setState, uses transactions for batching, and updates the DOM through virtual DOM diffing.
Angular 1
Dirty Checking
Angular 1 traverses all scopes from
$rootScope, comparing each watcher’s previous and current values to decide whether to update the DOM.
Watchers contain
eq,
exp,
fn,
get, and
lastfields.
$apply
Angular 1 triggers dirty checking by calling
$scope.$apply(). The framework automatically invokes
$applyfor built‑in events, timers, and $http, but developers must call it manually when using external libraries.
When code runs outside Angular’s context (e.g., jQuery event handlers),
$applymust be invoked manually to trigger change detection.
Summary: Angular 1 relies on manual or framework‑wrapped
$applyto perform dirty checking and batch updates.
Angular 2
Angular 2 traverses the component tree from the root, comparing old and new data to decide updates. It uses a unidirectional data flow and offers change‑detection strategies such as
OnPush, which checks object references instead of deep traversal.
It can perform hundreds of thousands of checks within a couple of milliseconds. — Pascal Precht
Images illustrate the default and OnPush strategies.
Zone.js
Angular 2 uses Zone.js to capture the execution context of asynchronous operations (setTimeout, XHR, event listeners). Zone.js patches these APIs and provides hooks that trigger change detection after each task.
When the main function and a timeout finish, Zone.js notifies Angular to run a digest cycle, enabling batch updates without manual calls.
Summary: Zone.js allows Angular 2 to perform automatic batch updates in any asynchronous context.
Vue
Vue creates a watcher for each data binding using
Object.definePropertyto define getters and setters, allowing it to detect changes.
setter
When data changes, Vue batches updates by queuing them within the same event loop, flushing the queue on the next tick. This behavior is consistent across events, timers, and XHR.
Asynchronous Update Queue
Whenever a data change is observed, Vue pushes it into a queue; duplicate watchers are de‑duplicated. The queue is flushed on the next event loop tick, using MutationObserver or setTimeout(fn, 0) as a fallback.
Vue’s implementation leverages JavaScript’s single‑threaded nature and the event queue to achieve batch updates.
config.async
Setting
Vue.config.async = falsedisables the asynchronous queue, causing synchronous DOM updates, which is useful for debugging but not recommended for production.
If async mode is disabled, Vue updates the DOM synchronously, which may degrade performance and affect watcher callback order.
Summary: Vue detects changes via getters/setters, batches updates using an async queue, and can be forced into synchronous mode for debugging.
Conclusion
This analysis compares the change‑detection and batch‑update mechanisms of React, Angular 1/2, and Vue. React and Angular 1 use execution context to batch updates, Angular 2 relies on Zone.js, and Vue employs ES5 getters/setters with the JavaScript event loop to achieve efficient batch updates.
Tencent IMWeb Frontend Team
IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.