Learn how to create derived reactive state using computed() from Vue’s reactivity system.
Computed properties are reactive values that are derived from other reactive state. They are cached and only re-evaluated when their dependencies change.
From packages/reactivity/src/computed.ts:47-154, the ComputedRefImpl class:
class ComputedRefImpl<T = any> implements Subscriber { _value: any = undefined readonly dep: Dep = new Dep(this) readonly __v_isRef = true readonly __v_isReadonly: boolean deps?: Link = undefined depsTail?: Link = undefined flags: EffectFlags = EffectFlags.DIRTY globalVersion: number = globalVersion - 1 constructor( public fn: ComputedGetter<T>, private readonly setter: ComputedSetter<T> | undefined, isSSR: boolean ) { this.__v_isReadonly = !setter this.isSSR = isSSR } get value(): T { const link = this.dep.track() // Track dependencies refreshComputed(this) // Re-evaluate if needed if (link) { link.version = this.dep.version } return this._value } set value(newValue) { if (this.setter) { this.setter(newValue) } else if (__DEV__) { warn('Write operation failed: computed value is readonly') } }}
Computed properties are lazy - they only re-evaluate when accessed and their dependencies have changed. This is more efficient than using a method that runs on every render.
Computed properties are cached based on their reactive dependencies:
<script setup>import { ref, computed } from 'vue'const count = ref(1)// Cached - depends on reactive countconst doubled = computed(() => count.value * 2)// NOT cached - depends on Date.now() which is not reactiveconst now = computed(() => Date.now())</script>
Computed properties that depend on non-reactive values (like Date.now()) will not update automatically. For such cases, use a method or a watcher instead.
Computed getters should not have side effects. Don’t modify other state, make async requests, or mutate the DOM inside a computed getter.
// Bad - has side effectsconst doubled = computed(() => { count.value++ // Don't mutate other state! return count.value * 2})// Good - pure functionconst doubled = computed(() => count.value * 2)
2
Avoid mutating computed return values
The value returned from a computed property is derived state. Think of it as a temporary snapshot - don’t mutate it directly.
// Bad - mutating computed valueconst items = computed(() => [1, 2, 3])items.value.push(4) // Don't mutate!// Good - create a new ref if you need to mutateconst mutableItems = ref([...items.value])mutableItems.value.push(4)
3
Use computed for expensive operations
If you have expensive data transformations, use computed properties to cache the results.
The computed exported from vue is enhanced in packages/runtime-core/src/apiComputed.ts:4-17:
export const computed: typeof _computed = ( getterOrOptions: any, debugOptions?: any,) => { const c = _computed(getterOrOptions, debugOptions, isInSSRComponentSetup) if (__DEV__) { const i = getCurrentInstance() if (i && i.appContext.config.warnRecursiveComputed) { (c as unknown as ComputedRefImpl<any>)._warnRecursive = true } } return c as any}
This adds SSR support and recursive computed warnings in development mode.