Vue.js Reactive API (reactive, ref, readonly)

In the Vue.js ecosystem, reactive programming serves as the cornerstone for building dynamic user interfaces. Whether through the early Vue.options pattern or modern Composition API, both rely fundamentally on tracking data changes and automatically updating views. Understanding these three core tools—reactive, ref, and readonly—is key to mastering Vue's reactivity principles. This article delves into their definitions, application scenarios, and interrelationships to help developers build more efficient and maintainable applications.
reactive is a function in Vue 3 used to convert ordinary JavaScript objects into reactive objects. Unlike Vue 2's automatic wrapping via the data option, reactive offers more flexible low-level control by leveraging Proxy technology to intercept read and write operations on properties.

When using reactive, Vue creates a proxy object that maintains an internal dependency graph. Any modification to property values of this object triggers the update mechanism, subsequently re-rendering relevant components. This mechanism is particularly suitable for handling nested complex data structures because it recursively tracks changes in deep objects.

Basic Usage Example

import { reactive } from 'vue'

// Create a reactive object
const state = reactive({
  count: 0,
  name: 'Vue',
  details: {
    age: 25,
    city: 'Beijing'
  }
})

// Modifying properties triggers view updates
state.count++
state.details.city = 'Shanghai'

In the code above, state is an ordinary object, but under the influence of reactive, it becomes reactive. When you directly modify state.details.city, Vue captures this change and notifies all components depending on this data to update.

ref: Lightweight Reactivity for Reference Types

While reactive is suitable for objects and arrays, ref provides a more concise solution for primitive data types (such as strings, numbers, booleans) or state variables that need independent management. ref returns an object containing a .value property used to wrap the original data.

The primary advantage of using ref lies in its ability to avoid the overhead of frequently creating reactive objects within functional components, and it can provide clearer type inference and code structure in certain scenarios (such as asynchronous operations or computed properties).

Comparison Scenarios: ref vs reactive

  • Primitive Data Types: Using reactive({ count: 0 }) directly requires multiple levels of unpacking, whereas ref(0) is more intuitive.
  • Simple State Management: In the Composition API, if only a few independent variables need management, ref is often more readable than nested reactive objects.
import { ref } from 'vue'

// Create a reactive number reference
const count = ref(0)

// To modify the value, access .value
count.value++ 

console.log(count.value) // Outputs 1

readonly: Guardian Mechanism for Immutable Data

The readonly function is used to convert a reactive object into an "immutable" reactive object. This is particularly important in Vue 3, as Vue by default allows modification of reactive object properties (unless shallowRef or specific configurations are used). However, preventing accidental modifications is crucial in scenarios involving computed properties, template rendering contexts, or when data consistency needs to be guaranteed.

Using readonly ensures that developers will not cause state pollution due to misoperations when using this data for logical judgments or display, while also adhering to the best practices of "immutable data" in functional programming.

Practical Application Scenarios

import { ref, readonly } from 'vue'

const user = ref({
  id: 1,
  name: 'Alice',
  roles: ['admin', 'editor']
})

// Use a read-only view in computed properties or templates
const profileInfo = readonly(user.value)

// Attempting to modify the read-only object does not trigger reactive updates and does not throw an error (default behavior)
profileInfo.roles.push('moderator') // Silently fails, data remains unchanged

// If modification of the original data is needed, it must still go through ref
user.value.roles.push('moderator') 

Summary and Best Practices

reactive, ref, and readonly together form the core pillars of Vue.js's reactive system. The choice of tool depends on the data type and management complexity: prioritize reactive for complex nested objects; use ref for primitive types or independent states; and always use readonly when freezing data states to ensure data integrity.

In practical development, reasonably applying these tools not only enhances code readability but also reduces potential runtime errors. As the Vue.js ecosystem continues to evolve, mastering these underlying mechanisms will help you confidently master modern frontend development.