0
# Computed Properties
1
2
Derived reactive state that automatically updates when dependencies change. Computed properties provide cached, derived values that recalculate only when their reactive dependencies change.
3
4
## Capabilities
5
6
### Read-only Computed
7
8
Creates a computed property with a getter function that automatically tracks dependencies and caches results.
9
10
```typescript { .api }
11
/**
12
* Creates a read-only computed property
13
* @param getter - Function that computes the value
14
* @returns Read-only computed reference
15
*/
16
function computed<T>(getter: ComputedGetter<T>): ComputedRef<T>;
17
18
type ComputedGetter<T> = () => T;
19
20
interface ComputedRef<T = any> extends WritableComputedRef<T> {
21
readonly value: T;
22
}
23
```
24
25
**Usage Examples:**
26
27
```typescript
28
import { ref, computed } from "@vue/composition-api";
29
30
const count = ref(0);
31
const doubleCount = computed(() => count.value * 2);
32
33
console.log(doubleCount.value); // 0
34
count.value = 5;
35
console.log(doubleCount.value); // 10
36
37
// Complex computed with multiple dependencies
38
const firstName = ref("John");
39
const lastName = ref("Doe");
40
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
41
42
console.log(fullName.value); // "John Doe"
43
```
44
45
### Writable Computed
46
47
Creates a computed property with both getter and setter functions, allowing two-way binding and derived state manipulation.
48
49
```typescript { .api }
50
/**
51
* Creates a writable computed property
52
* @param options - Object with get and set functions
53
* @returns Writable computed reference
54
*/
55
function computed<T>(options: WritableComputedOptions<T>): WritableComputedRef<T>;
56
57
interface WritableComputedOptions<T> {
58
get: ComputedGetter<T>;
59
set: ComputedSetter<T>;
60
}
61
62
type ComputedSetter<T> = (value: T) => void;
63
64
interface WritableComputedRef<T> extends Ref<T> {
65
readonly effect: ReactiveEffect<T>;
66
}
67
```
68
69
**Usage Examples:**
70
71
```typescript
72
import { ref, computed } from "@vue/composition-api";
73
74
const firstName = ref("John");
75
const lastName = ref("Doe");
76
77
const fullName = computed({
78
get: () => `${firstName.value} ${lastName.value}`,
79
set: (value: string) => {
80
const parts = value.split(" ");
81
firstName.value = parts[0] || "";
82
lastName.value = parts[1] || "";
83
},
84
});
85
86
console.log(fullName.value); // "John Doe"
87
88
// Setting the computed value updates the underlying refs
89
fullName.value = "Jane Smith";
90
console.log(firstName.value); // "Jane"
91
console.log(lastName.value); // "Smith"
92
```
93
94
### Advanced Computed Patterns
95
96
Advanced usage patterns for computed properties including conditional logic, async operations, and error handling.
97
98
**Conditional Computed:**
99
100
```typescript
101
import { ref, computed } from "@vue/composition-api";
102
103
const user = ref<{ name: string; email?: string } | null>(null);
104
const displayName = computed(() => {
105
if (!user.value) return "Guest";
106
return user.value.email ? `${user.value.name} (${user.value.email})` : user.value.name;
107
});
108
109
// Computed with fallback values
110
const safeValue = computed(() => user.value?.name ?? "Unknown");
111
```
112
113
**Computed with Complex Logic:**
114
115
```typescript
116
import { ref, reactive, computed } from "@vue/composition-api";
117
118
const items = ref([
119
{ id: 1, name: "Apple", category: "fruit", price: 1.2 },
120
{ id: 2, name: "Banana", category: "fruit", price: 0.8 },
121
{ id: 3, name: "Carrot", category: "vegetable", price: 0.6 },
122
]);
123
124
const filters = reactive({
125
category: "",
126
maxPrice: null as number | null,
127
searchTerm: "",
128
});
129
130
const filteredItems = computed(() => {
131
return items.value.filter((item) => {
132
const matchesCategory = !filters.category || item.category === filters.category;
133
const matchesPrice = !filters.maxPrice || item.price <= filters.maxPrice;
134
const matchesSearch = !filters.searchTerm ||
135
item.name.toLowerCase().includes(filters.searchTerm.toLowerCase());
136
137
return matchesCategory && matchesPrice && matchesSearch;
138
});
139
});
140
141
const itemStats = computed(() => ({
142
total: filteredItems.value.length,
143
avgPrice: filteredItems.value.reduce((sum, item) => sum + item.price, 0) / filteredItems.value.length || 0,
144
categories: [...new Set(filteredItems.value.map(item => item.category))],
145
}));
146
```
147
148
**Computed with Side Effects (Anti-pattern Warning):**
149
150
```typescript
151
import { ref, computed, watch } from "@vue/composition-api";
152
153
// ❌ Don't do this - computed should be pure
154
const badComputed = computed(() => {
155
console.log("This runs on every access!"); // Side effect
156
return someValue.value * 2;
157
});
158
159
// ✅ Use watchers for side effects instead
160
const someValue = ref(0);
161
const doubledValue = computed(() => someValue.value * 2);
162
163
watch(doubledValue, (newValue) => {
164
console.log("Doubled value changed:", newValue);
165
});
166
```
167
168
### Performance Considerations
169
170
Computed properties are cached and only recalculate when dependencies change, making them efficient for expensive operations.
171
172
```typescript
173
import { ref, computed } from "@vue/composition-api";
174
175
const expensiveData = ref([/* large array */]);
176
177
// This computation only runs when expensiveData changes
178
const processedData = computed(() => {
179
console.log("Processing data..."); // Only logs when dependencies change
180
return expensiveData.value
181
.filter(item => item.active)
182
.map(item => ({ ...item, processed: true }))
183
.sort((a, b) => a.priority - b.priority);
184
});
185
186
// Multiple accesses use the cached result
187
console.log(processedData.value); // Processes data
188
console.log(processedData.value); // Uses cache
189
console.log(processedData.value); // Uses cache
190
```
191
192
### Computed in Component Setup
193
194
Typical usage patterns within Vue component setup functions.
195
196
```typescript
197
import { defineComponent, ref, computed } from "@vue/composition-api";
198
199
export default defineComponent({
200
props: {
201
multiplier: {
202
type: Number,
203
default: 1,
204
},
205
},
206
setup(props) {
207
const baseValue = ref(10);
208
209
// Computed property using props and reactive state
210
const computedValue = computed(() => baseValue.value * props.multiplier);
211
212
// Computed property for template usage
213
const isEven = computed(() => computedValue.value % 2 === 0);
214
215
// Writable computed for v-model compatibility
216
const doubledBase = computed({
217
get: () => baseValue.value * 2,
218
set: (value) => {
219
baseValue.value = value / 2;
220
},
221
});
222
223
return {
224
baseValue,
225
computedValue,
226
isEven,
227
doubledBase,
228
};
229
},
230
});
231
```
232
233
## Types
234
235
```typescript { .api }
236
interface ComputedRef<T = any> extends WritableComputedRef<T> {
237
readonly value: T;
238
}
239
240
interface WritableComputedRef<T> extends Ref<T> {
241
readonly effect: ReactiveEffect<T>;
242
}
243
244
interface WritableComputedOptions<T> {
245
get: ComputedGetter<T>;
246
set: ComputedSetter<T>;
247
}
248
249
type ComputedGetter<T> = () => T;
250
type ComputedSetter<T> = (value: T) => void;
251
252
interface ReactiveEffect<T = any> {
253
(): T;
254
_isEffect: true;
255
id: number;
256
active: boolean;
257
raw: () => T;
258
deps: Array<Dep>;
259
options: ReactiveEffectOptions;
260
}
261
262
interface ReactiveEffectOptions {
263
lazy?: boolean;
264
scheduler?: (job: ReactiveEffect) => void;
265
onTrack?: (event: DebuggerEvent) => void;
266
onTrigger?: (event: DebuggerEvent) => void;
267
onStop?: () => void;
268
}
269
```