🚀 LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
🎓 COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
HTML MASTER CLASS /// LEARN TAGS /// BUILD STRUCTURE /// SEMANTIC WEB /// HTML MASTER CLASS /// LEARN TAGS ///

Reactivity: ref vs reactive in Vue.js

Learn about Reactivity: ref vs reactive in this comprehensive Vue.js tutorial. Understand the difference between ref() and reactive(), and how Vue's reactivity system works.

Total XP: 0|💻 react XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

Select an unlocked node to view details root

🚀 LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
🎓 COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

Learn how Vue tracks changes and updates the DOM automatically.

1What is Reactivity?

Reactivity means that when the state (data) of your application changes, the DOM (UI) updates automatically to reflect that change. You don't have to write document.getElementById('text').innerHTML = newText ever again.

2The `ref()` function

ref() takes an inner value and returns a reactive and mutable ref object, which has a single property .value. You must use .value in JavaScript, but in the <template>, Vue auto-unwraps it.

3The `reactive()` function

reactive() takes an object and returns a proxy of that object. It does not use .value, making the code look like vanilla JS. However, you cannot destructure a reactive object without losing its reactivity.

4Step-by-Step Breakdown

Reactivity is the heart of Vue. When you update a variable, the UI updates automatically. But regular JavaScript variables are NOT reactive.

To make a primitive value (like a Number, String, or Boolean) reactive in the Composition API, we wrap it in a ref.

Which function is used to declare a reactive state for primitive values (like numbers or strings)?

  • reactive
  • ref
  • useState

Wait! If count is a ref, how do you change its value? You MUST access its .value property inside the <script> tag.

How do you modify the underlying value of a ref inside the JavaScript <script setup> block?

  • score.value
  • score.current
  • setScore

In the <template>, however, Vue is smart. It automatically "unwraps" the ref for you, so you don't need to write .value.

What if you have an Object with multiple properties? You can use ref, but Vue provides another tool called reactive specifically for Objects.

Unlike ref, reactive does NOT require .value. You just access the properties directly.

When using reactive to declare an object, do you need to use .value to access its properties?

  • active
  • value.active

Rule of thumb: Use ref() for everything (primitives, arrays, objects). It is the most robust and universal approach in modern Vue 3.

Level Up 🚀

Advanced cheat sheets, SEO tricks, and interview prep for this topic.

Browser Support

ChromeSupported

Fully supported.

FirefoxSupported

Fully supported.

SafariSupported

Fully supported.

EdgeSupported

Fully supported.

Accessibility (A11y)

1Reactive Live-Region Announcements

A ref like const statusMessage = ref('') bound to an aria-live="polite" region lets screen readers automatically announce asynchronous state changes — like 'Item added to cart' — the instant the ref updates, without manually calling any announcement API.

<div aria-live="polite">{{ statusMessage }}</div>

SEO Implications

  • 1

    Reactive Primitives Are Resolved to Plain Values Before Reaching the Crawler

    Whether internal state is stored in a ref or a reactive() object makes no difference to indexing: by the time Vue's server renderer produces the HTML string, every {{ ref.value }} interpolation has already been unwrapped to plain text, so the reactivity mechanism itself is invisible in the response a crawler downloads.

Best Practices

Default to ref() for Everything

Because reactive() loses reactivity when destructured and cannot hold primitive values re-assignably, most Vue style guides now recommend using ref() universally — including for objects and arrays — and reserving reactive() for cases with a strong reason not to.

Frequent Bugs

THE BUG

Destructuring a reactive() object and losing reactivity.

THE FIX

const { name, age } = reactive({ name: 'A', age: 1 }) copies name and age out as disconnected plain values — future mutations to the original object won't update them. Either reference the object's properties directly (state.name) or convert it with toRefs(state) before destructuring.

Real-World Examples

A Multi-Step Form's Local State

A checkout wizard stores its entire draft order in one const order = reactive({ items: [], shipping: null, payment: null }) object, mutating nested fields directly (order.shipping = selected) across three separate step components without ever reassigning the whole object.

const order = reactive({ items: [], shipping: null });
function selectShipping(method) {
  order.shipping = method; // direct mutation, fully reactive
}

Interview Prep

?Frequently Asked Questions

Pascual Vila

Pascual Vila

Frontend Instructor // Code Syllabus

Common Pitfalls & Errors

The Error //

Mutating a Prop Directly

// Wrong const props = defineProps(['count']); function increment() { props.count++; } // Correct const emit = defineEmits(['update:count']); function increment() { emit('update:count', props.count + 1); }

The Solution //

A child component should never assign to a prop it received (e.g. props.title = 'New'). Vue logs "Unexpected mutation of prop" because props are a one-way binding. Copy the prop into local state with ref()/computed() first, or emit an event asking the parent to change its own data.

The Error //

Losing Reactivity by Destructuring reactive()

// Wrong const { name } = reactive({ name: 'Alice' }); // name is now a static string // Correct const state = reactive({ name: 'Alice' }); const { name } = toRefs(state); // name is a live ref

The Solution //

Destructuring a reactive() object copies its properties out as disconnected plain values, so future mutations of the original object won't update the destructured variables. Keep referencing the object's properties directly, or convert it with toRefs() before destructuring.

Continue Learning