Derive state intelligently with computed properties.
1What is a Computed Property?
A computed property allows you to define a property that is used the same way as data, but can also have some custom logic that is evaluated to get its value. It is defined using the computed() function.
2The Magic of Caching
The main difference between a computed property and a normal function is caching. A computed property only re-evaluates when its reactive dependencies change. If you call a computed property 100 times, the logic only runs once, saving CPU cycles.
3Read-Only by Default
Computed properties should be treated as derived state, meaning you shouldn't mutate them directly. They are essentially 'getters'. (Though Vue does allow you to define writable computed properties by providing a set() function if truly needed).
4Step-by-Step Breakdown
Sometimes you need to derive new data from your existing reactive state. For example, if you have firstName and lastName, you might want fullName.
You could write a function to calculate this every time, but Vue offers a much better solution: computed properties.
A computed property tracks its dependencies. It only recalculates when one of those dependencies (like firstName) changes. Otherwise, it returns a cached result!
What is the main performance advantage of using computed over a standard function?
- โIt runs asynchronously
- โIt caches the result
- โIt uses less memory
In the template, you use a computed property exactly like a normal ref. You do NOT add parentheses () because it is not a method call.
How do you correctly output the value of a computed property named totalPrice in the template?
- โ{{ totalPrice() }}
- โ{{ totalPrice.value }}
- โ{{ totalPrice }}
Computed properties are extremely useful for filtering or sorting arrays without mutating the original array.
By default, computed properties are read-only. If you try to assign a value directly to fullName.value = "Jane Doe", Vue will throw a warning.
By default, are computed properties writable?
- โYes, they are writable
- โNo, they are read-only
Use computed whenever you have complex logic in your template. It keeps your templates clean and your app blazingly fast.
Level Up ๐
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Computed ARIA State
Deriving aria-expanded, aria-pressed, or aria-selected from a computed property (const ariaExpanded = computed(() => isOpen.value ? 'true' : 'false')) guarantees the attribute can never drift out of sync with the actual UI state the way a manually duplicated string literal could.
<button :aria-expanded="ariaExpanded">Menu</button>SEO Implications
- 1
Computed Properties Run Identically During SSR
Because computed() is pure synchronous JavaScript with no DOM access, it evaluates the same way on the server during server-side rendering as in the browser, so any text derived from a computed property โ a formatted price, a pluralized label โ is present in the very first HTML response a crawler downloads.
Best Practices
Keep Computed Getters Pure
A computed getter should never have side effects โ no API calls, no mutating other refs. Vue may re-evaluate a computed getter multiple times without a corresponding re-render, so side effects inside it can run an unpredictable number of times.
Prefer computed() Over a Method for Derived State
If a value only depends on other reactive state and takes no arguments, use computed() instead of a plain function so Vue can cache the result and skip recalculation on renders where the dependencies haven't changed.
Frequent Bugs
Calling a computed property like a function: {{ fullName() }}.
A computed ref is accessed like a property, not invoked like a method. Writing fullName() in the template throws or returns undefined depending on the value โ remove the parentheses and reference {{ fullName }} directly.
Real-World Examples
Filtering and Sorting a Product List
An e-commerce listing keeps the raw products array untouched and derives the visible list with a single computed(() => products.value.filter(p => p.inStock).sort((a,b) => a.price - b.price)), so toggling 'sort by price' never mutates the original fetched data.
const sortedInStock = computed(() =>
products.value
.filter(p => p.inStock)
.sort((a, b) => a.price - b.price)
);