Computed Properties
Deriving values from reactive state with computed(), and why it beats recalculating in a method or template expression.
읽는 데 2분
A lot of what you show in a UI isn't state itself — it's something derived from state. A full name derived from first and last name, a filtered list derived from a search term, a total derived from cart items. Vue's computed() is built exactly for this.
<script setup>
import { ref, computed } from "vue";
const firstName = ref("Ada");
const lastName = ref("Lovelace");
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
</script>
<template>
<p>{{ fullName }}</p>
</template>computed() takes a function and returns a ref-like object whose .value holds the function's result. You use it in the template the same way you'd use a ref — no parentheses, since it's a value, not a method to call.
Why not just use a method?
You could get the same displayed result with a plain function:
<script setup>
function fullName() {
return `${firstName.value} ${lastName.value}`;
}
</script>
<template>
<p>{{ fullName() }}</p>
</template>The difference is caching. A computed property only re-runs its function when one of the reactive values it reads (firstName.value, lastName.value) actually changes. Call fullName five times in a render without either name changing, and Vue reuses the cached result instead of recomputing it. A method, by contrast, re-runs every single time it's called — including once per re-render, even if nothing it depends on has changed. For a cheap string concatenation this barely matters; for filtering a large list or doing any real computation, it matters a lot.
A more realistic example
<script setup>
import { ref, computed } from "vue";
const items = ref([
{ name: "Keyboard", price: 60 },
{ name: "Mouse", price: 25 },
{ name: "Monitor", price: 200 },
]);
const total = computed(() =>
items.value.reduce((sum, item) => sum + item.price, 0)
);
const expensiveItems = computed(() =>
items.value.filter((item) => item.price > 50)
);
</script>
<template>
<p>Total: ${{ total }}</p>
<ul>
<li v-for="item in expensiveItems" :key="item.name">{{ item.name }}</li>
</ul>
</template>Both total and expensiveItems automatically recompute whenever items changes (adding, removing, or editing an item) and stay cached otherwise — you never manually call a function to "refresh" them.
Computed properties are read-only by default
Trying to assign to total.value = 500 directly would throw a warning — a computed property is meant to be a pure, derived view of other state, not a separate piece of state you can set independently. If you genuinely need a settable computed value (rare), computed() accepts an object with get and set functions instead of a single function, but reach for a plain ref first if you find yourself wanting this often.