0
# Reactive References
1
2
Reactive references provide fine-grained reactivity for primitive values and objects by wrapping them in a reactive container that tracks access and mutations.
3
4
## Capabilities
5
6
### ref()
7
8
Creates a reactive and mutable ref object with a single `.value` property that holds the wrapped value.
9
10
```typescript { .api }
11
/**
12
* Creates a reactive and mutable ref object
13
* @param value - The value to wrap in a ref
14
* @returns A reactive ref object with a `.value` property
15
*/
16
function ref<T>(value: T): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T>;
17
function ref<T = any>(): Ref<T | undefined>;
18
19
interface Ref<T = any, S = T> {
20
get value(): T;
21
set value(_: S);
22
[RefSymbol]: true;
23
}
24
```
25
26
**Usage Examples:**
27
28
```typescript
29
import { ref } from "@vue/reactivity";
30
31
// Basic ref usage
32
const count = ref(0);
33
console.log(count.value); // 0
34
count.value = 5;
35
console.log(count.value); // 5
36
37
// Object ref (will be deeply reactive)
38
const user = ref({ name: "Alice", age: 25 });
39
user.value.name = "Bob"; // Triggers reactivity
40
user.value = { name: "Charlie", age: 30 }; // Triggers reactivity
41
42
// Array ref
43
const items = ref([1, 2, 3]);
44
items.value.push(4); // Triggers reactivity
45
items.value = [5, 6, 7]; // Triggers reactivity
46
```
47
48
### shallowRef()
49
50
Creates a shallow reactive ref where only the `.value` access is reactive, not the object itself.
51
52
```typescript { .api }
53
/**
54
* Creates a shallow reactive ref - only .value access is reactive
55
* @param value - The value to wrap in a shallow ref
56
* @returns A shallow ref object
57
*/
58
function shallowRef<T>(value: T): ShallowRef<T>;
59
function shallowRef<T = any>(): ShallowRef<T | undefined>;
60
61
interface ShallowRef<T = any, S = T> extends Ref<T, S> {
62
[ShallowRefMarker]?: true;
63
}
64
```
65
66
**Usage Examples:**
67
68
```typescript
69
import { shallowRef, triggerRef } from "@vue/reactivity";
70
71
const obj = shallowRef({ count: 1 });
72
73
// This will NOT trigger effects because shallow refs only track .value access
74
obj.value.count = 2;
75
76
// To trigger effects after mutating, use triggerRef
77
triggerRef(obj);
78
79
// This WILL trigger effects (replacing .value)
80
obj.value = { count: 3 };
81
```
82
83
### isRef()
84
85
Checks if a value is a ref object.
86
87
```typescript { .api }
88
/**
89
* Checks if a value is a ref object
90
* @param r - Value to check
91
* @returns True if the value is a ref
92
*/
93
function isRef<T>(r: Ref<T> | unknown): r is Ref<T>;
94
function isRef(r: any): r is Ref;
95
```
96
97
**Usage Examples:**
98
99
```typescript
100
import { ref, isRef } from "@vue/reactivity";
101
102
const count = ref(0);
103
const plainValue = 42;
104
105
console.log(isRef(count)); // true
106
console.log(isRef(plainValue)); // false
107
console.log(isRef({ value: 42 })); // false (not a real ref)
108
```
109
110
### unref()
111
112
Returns the inner value if the argument is a ref, otherwise returns the argument itself.
113
114
```typescript { .api }
115
/**
116
* Returns the inner value if the argument is a ref, otherwise returns the argument
117
* @param ref - A ref or any value
118
* @returns The unwrapped value
119
*/
120
function unref<T>(ref: MaybeRef<T> | ComputedRef<T>): T;
121
```
122
123
**Usage Examples:**
124
125
```typescript
126
import { ref, unref } from "@vue/reactivity";
127
128
const count = ref(42);
129
const plainValue = 100;
130
131
console.log(unref(count)); // 42
132
console.log(unref(plainValue)); // 100
133
134
// Useful for functions that accept both refs and plain values
135
function useValue(maybeRef: MaybeRef<number>): number {
136
return unref(maybeRef) * 2;
137
}
138
139
console.log(useValue(count)); // 84
140
console.log(useValue(50)); // 100
141
```
142
143
### toValue()
144
145
Normalizes values/refs/getters to values. Similar to `unref` but also handles getter functions.
146
147
```typescript { .api }
148
/**
149
* Normalizes values/refs/getters to values
150
* @param source - A ref, getter function, or plain value
151
* @returns The resolved value
152
*/
153
function toValue<T>(source: MaybeRefOrGetter<T>): T;
154
```
155
156
**Usage Examples:**
157
158
```typescript
159
import { ref, toValue } from "@vue/reactivity";
160
161
const count = ref(42);
162
const getValue = () => 100;
163
const plainValue = 200;
164
165
console.log(toValue(count)); // 42
166
console.log(toValue(getValue)); // 100
167
console.log(toValue(plainValue)); // 200
168
```
169
170
### toRef()
171
172
Normalizes values/refs/getters into refs, or creates a ref for a property on a reactive object.
173
174
```typescript { .api }
175
/**
176
* Converts a value to a ref
177
* @param value - Value to convert to ref
178
* @returns A ref containing the value
179
*/
180
function toRef<T>(value: T): ToRef<T>;
181
182
/**
183
* Creates a ref for a property on a reactive object
184
* @param object - Reactive object
185
* @param key - Property key
186
* @returns A ref linked to the object property
187
*/
188
function toRef<T extends object, K extends keyof T>(object: T, key: K): ToRef<T[K]>;
189
190
/**
191
* Creates a ref for a property with a default value
192
* @param object - Reactive object
193
* @param key - Property key
194
* @param defaultValue - Default value if property is undefined
195
* @returns A ref linked to the object property with default
196
*/
197
function toRef<T extends object, K extends keyof T>(
198
object: T,
199
key: K,
200
defaultValue: T[K]
201
): ToRef<Exclude<T[K], undefined>>;
202
```
203
204
**Usage Examples:**
205
206
```typescript
207
import { reactive, toRef } from "@vue/reactivity";
208
209
const state = reactive({ count: 0, name: "Vue" });
210
211
// Create refs from reactive object properties
212
const countRef = toRef(state, "count");
213
const nameRef = toRef(state, "name");
214
215
console.log(countRef.value); // 0
216
countRef.value = 5; // Updates state.count
217
console.log(state.count); // 5
218
219
// Convert plain value to ref
220
const plainRef = toRef(42);
221
console.log(plainRef.value); // 42
222
```
223
224
### toRefs()
225
226
Converts a reactive object to a plain object where each property is a ref that maintains reactivity connection to the original object.
227
228
```typescript { .api }
229
/**
230
* Converts a reactive object to refs for each property
231
* @param object - Reactive object to convert
232
* @returns Object with ref properties
233
*/
234
function toRefs<T extends object>(object: T): ToRefs<T>;
235
```
236
237
**Usage Examples:**
238
239
```typescript
240
import { reactive, toRefs } from "@vue/reactivity";
241
242
const state = reactive({
243
count: 0,
244
name: "Vue",
245
items: [1, 2, 3]
246
});
247
248
// Convert to refs - useful for destructuring
249
const { count, name, items } = toRefs(state);
250
251
console.log(count.value); // 0
252
count.value = 10; // Updates state.count
253
console.log(state.count); // 10
254
255
// Commonly used in composition functions
256
function useCounter() {
257
const state = reactive({ count: 0 });
258
259
return {
260
...toRefs(state),
261
increment: () => state.count++
262
};
263
}
264
```
265
266
### customRef()
267
268
Creates a customized ref with explicit control over dependency tracking and updates.
269
270
```typescript { .api }
271
/**
272
* Creates a customized ref with explicit control over tracking and triggering
273
* @param factory - Factory function that receives track and trigger callbacks
274
* @returns A custom ref object
275
*/
276
function customRef<T>(factory: CustomRefFactory<T>): Ref<T>;
277
278
type CustomRefFactory<T> = (
279
track: () => void,
280
trigger: () => void
281
) => {
282
get: () => T;
283
set: (value: T) => void;
284
};
285
```
286
287
**Usage Examples:**
288
289
```typescript
290
import { customRef } from "@vue/reactivity";
291
292
// Debounced ref that delays updates
293
function useDebouncedRef<T>(value: T, delay = 200) {
294
let timeout: number;
295
296
return customRef<T>((track, trigger) => {
297
return {
298
get() {
299
track(); // Track dependency
300
return value;
301
},
302
set(newValue: T) {
303
clearTimeout(timeout);
304
timeout = setTimeout(() => {
305
value = newValue;
306
trigger(); // Trigger updates
307
}, delay);
308
}
309
};
310
});
311
}
312
313
const debouncedValue = useDebouncedRef("hello");
314
```
315
316
### triggerRef()
317
318
Force trigger effects that depend on a shallow ref. Used when you have made deep mutations to the inner value of a shallow ref.
319
320
```typescript { .api }
321
/**
322
* Force trigger effects that depend on a shallow ref
323
* @param ref - The shallow ref to trigger
324
*/
325
function triggerRef(ref: Ref): void;
326
```
327
328
**Usage Examples:**
329
330
```typescript
331
import { shallowRef, triggerRef, effect } from "@vue/reactivity";
332
333
const obj = shallowRef({ count: 1 });
334
335
effect(() => {
336
console.log("Count:", obj.value.count);
337
});
338
339
// This won't trigger the effect (shallow ref)
340
obj.value.count = 2;
341
342
// Manually trigger effects after mutation
343
triggerRef(obj); // Now the effect runs
344
```
345
346
### proxyRefs()
347
348
Returns a proxy that shallowly unwraps properties that are refs, allowing direct property access without `.value`.
349
350
```typescript { .api }
351
/**
352
* Creates a proxy that automatically unwraps ref properties
353
* @param objectWithRefs - Object containing ref properties
354
* @returns Proxy with automatic ref unwrapping
355
*/
356
function proxyRefs<T extends object>(objectWithRefs: T): ShallowUnwrapRef<T>;
357
```
358
359
**Usage Examples:**
360
361
```typescript
362
import { ref, proxyRefs } from "@vue/reactivity";
363
364
const refs = {
365
count: ref(0),
366
name: ref("Vue"),
367
plainValue: 42
368
};
369
370
const proxy = proxyRefs(refs);
371
372
// Access without .value
373
console.log(proxy.count); // 0 (unwrapped from ref)
374
console.log(proxy.name); // "Vue" (unwrapped from ref)
375
console.log(proxy.plainValue); // 42 (plain value)
376
377
// Assignment unwraps refs
378
proxy.count = 5; // Same as refs.count.value = 5
379
proxy.name = "React"; // Same as refs.name.value = "React"
380
```
381
382
## Types
383
384
```typescript { .api }
385
// Core ref types
386
type MaybeRef<T = any> = T | Ref<T> | ShallowRef<T> | WritableComputedRef<T>;
387
type MaybeRefOrGetter<T = any> = MaybeRef<T> | ComputedRef<T> | (() => T);
388
389
// Conversion types
390
type ToRef<T> = IfAny<T, Ref<T>, [T] extends [Ref] ? T : Ref<T>>;
391
type ToRefs<T = any> = {
392
[K in keyof T]: ToRef<T[K]>;
393
};
394
395
// Unwrapping types
396
type UnwrapRef<T> = T extends ShallowRef<infer V, unknown>
397
? V
398
: T extends Ref<infer V, unknown>
399
? UnwrapRefSimple<V>
400
: UnwrapRefSimple<T>;
401
402
type ShallowUnwrapRef<T> = {
403
[K in keyof T]: DistributeRef<T[K]>;
404
};
405
406
// Custom ref factory type
407
type CustomRefFactory<T> = (
408
track: () => void,
409
trigger: () => void
410
) => {
411
get: () => T;
412
set: (value: T) => void;
413
};
414
```