Vue Tutorial menu

Vue Reactivity: ref, reactive and computed

Reactive data is data that Vue watches, so the page updates whenever it changes.

Plain Variables Are Not Reactive

In the earlier lessons we used plain const values. If you change a plain variable, Vue does not know, and the page stays the same. To make data reactive, use ref() or reactive().

ref()

ref() wraps a value and makes it reactive. It works with any type: numbers, strings, booleans, arrays and objects.

Example

vue
<script setup>
import { ref } from "vue";

const likes = ref(0);

function like() {
  likes.value++;
}
</script>

<template>
  <p>This post has {{ likes }} likes</p>
  <button @click="like">Like</button>
</template>
Output
This post has 0 likes
(after 2 clicks)
This post has 2 likes

The important rule:

WhereHow to read a ref
In <script setup>likes.value
In <template>likes (Vue adds .value for you)

Forgetting .value in the script is the most common Vue 3 mistake. If a number does not change, check this first.

reactive()

reactive() makes a whole object reactive. You do not need .value with it.

Example

vue
<script setup>
import { reactive } from "vue";

const order = reactive({
  item: "Chicken Biryani",
  plates: 1,
  pricePerPlate: 450,
});

function addPlate() {
  order.plates++;
}
</script>

<template>
  <p>{{ order.plates }} x {{ order.item }}</p>
  <button @click="addPlate">Add plate</button>
</template>

reactive() only works with objects and arrays, and you should not replace the whole object (order = {...}), or it loses reactivity. Because of these limits, many developers simply use ref() for everything.

computed()

A computed value is calculated from other reactive data. Vue remembers the result and recalculates it only when the data it uses changes.

Example

vue
<script setup>
import { ref, computed } from "vue";

const plates = ref(2);
const pricePerPlate = 450;

const total = computed(() => plates.value * pricePerPlate);
const message = computed(() => (total.value > 1000 ? "Free delivery!" : "Delivery Rs 150"));
</script>

<template>
  <p>Plates: {{ plates }}</p>
  <p>Total: Rs {{ total }}</p>
  <p>{{ message }}</p>
  <button @click="plates++">Add plate</button>
</template>
Output
Plates: 2
Total: Rs 900
Delivery Rs 150
(after 1 click)
Plates: 3
Total: Rs 1350
Free delivery!

Use computed values instead of long expressions in the template. Your template stays clean, and the logic is in one place.

Computed vs a Function

You could also write a function function total() { ... } and call {{ total() }}. The difference:

  • A computed value is cached and recalculated only when its data changes
  • A function runs again on every render

For values derived from data, prefer computed.

watch()

Sometimes you want to do something when data changes, such as saving it or calling an API. Use watch():

Example

vue
<script setup>
import { ref, watch } from "vue";

const city = ref("Karachi");

watch(city, (newCity, oldCity) => {
  console.log(`City changed from ${oldCity} to ${newCity}`);
});
</script>

<template>
  <button @click="city = 'Lahore'">Move to Lahore</button>
</template>
Output
City changed from Karachi to Lahore

Which One to Use?

ToolUse it when
ref()You need any reactive value (the default choice)
reactive()You want a reactive object without .value
computed()A value is calculated from other values
watch()You need to run code (a side effect) when something changes

Exercise

Exercise

Inside <script setup>, how do you add 1 to a ref called count?

Learn Vue with a teacher

Join the Full Stack Development course at Workownix, online or in Orangi Town, Karachi, and get a certificate.

See the course Ask on WhatsApp