Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Computed properties

A computed property is a value that Vue derives from other state and recalculates when that state changes. For example, the number of unfinished tasks depends on the task list, so there is no need to store it separately.

The computed function

In this lesson tasks are objects with id, text and done fields:

<!-- src/App.vue -->
<script setup>
import { ref, computed } from 'vue'
 
const todos = ref([
  { id: 1, text: 'Buy bread', done: true },
  { id: 2, text: 'Call Anna', done: false },
  { id: 3, text: 'Write a report', done: false },
])
 
const remaining = computed(() => {
  return todos.value.filter((todo) => !todo.done).length
})
</script>
 
<template>
  <p>Tasks left: {{ remaining }}</p>
</template>

The page shows "Tasks left: 2". computed takes a function that returns a value and creates an object similar to a ref: in the template it is just remaining, in the script remaining.value.

Recalculation

Vue remembers which reactive data the function read. When that data changes, the value is recalculated by itself:

<script setup>
import { ref, computed } from 'vue'
 
const todos = ref([
  { id: 1, text: 'Buy bread', done: false },
  { id: 2, text: 'Call Anna', done: false },
])
 
const remaining = computed(() => todos.value.filter((t) => !t.done).length)
 
function finishFirst() {
  todos.value[0].done = true
}
</script>
 
<template>
  <p>Tasks left: {{ remaining }}</p>
  <button @click="finishFirst">Finish the first one</button>
</template>

At first the page shows "Tasks left: 2", after the click — "1".

A filtered list

computed is used most often for lists shown in a different form:

<script setup>
import { ref, computed } from 'vue'
 
const todos = ref([
  { id: 1, text: 'Buy bread', done: true },
  { id: 2, text: 'Call Anna', done: false },
])
const onlyActive = ref(false)
 
const visibleTodos = computed(() => {
  return onlyActive.value
    ? todos.value.filter((t) => !t.done)
    : todos.value
})
</script>

visibleTodos depends on both the list and the onlyActive flag. The v-for directive from the lists lesson will put such a list on the page.

Why computed beats a function

A function called in the template gives the same result: {{ countRemaining() }}. The difference is caching:

Functioncomputed
When it runsOn every re-renderOnly when its dependencies change
In the templatecountRemaining()remaining

If something unrelated to tasks changes on the page, the function still runs again, while computed returns the stored value.

Common mistake

Changing state inside computed:

<script setup>
const sorted = computed(() => todos.value.sort((a, b) => a.id - b.id))
</script>

sort reorders the original array — the computing function changes the very data it depends on. A computed property should only read and return. Sort a copy: [...todos.value].sort(...) or todos.value.toSorted(...).

Thanks for reading!

Donate to the site — we work hard for you.