Vue.js's standalone reactivity system providing reactive references, objects, computed values, effects, and watchers with fine-grained dependency tracking.
—
Reactive references provide fine-grained reactivity for primitive values and objects by wrapping them in a reactive container that tracks access and mutations.
Creates a reactive and mutable ref object with a single .value property that holds the wrapped value.
/**
* Creates a reactive and mutable ref object
* @param value - The value to wrap in a ref
* @returns A reactive ref object with a `.value` property
*/
function ref<T>(value: T): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T>;
function ref<T = any>(): Ref<T | undefined>;
interface Ref<T = any, S = T> {
get value(): T;
set value(_: S);
[RefSymbol]: true;
}Usage Examples:
import { ref } from "@vue/reactivity";
// Basic ref usage
const count = ref(0);
console.log(count.value); // 0
count.value = 5;
console.log(count.value); // 5
// Object ref (will be deeply reactive)
const user = ref({ name: "Alice", age: 25 });
user.value.name = "Bob"; // Triggers reactivity
user.value = { name: "Charlie", age: 30 }; // Triggers reactivity
// Array ref
const items = ref([1, 2, 3]);
items.value.push(4); // Triggers reactivity
items.value = [5, 6, 7]; // Triggers reactivityCreates a shallow reactive ref where only the .value access is reactive, not the object itself.
/**
* Creates a shallow reactive ref - only .value access is reactive
* @param value - The value to wrap in a shallow ref
* @returns A shallow ref object
*/
function shallowRef<T>(value: T): ShallowRef<T>;
function shallowRef<T = any>(): ShallowRef<T | undefined>;
interface ShallowRef<T = any, S = T> extends Ref<T, S> {
[ShallowRefMarker]?: true;
}Usage Examples:
import { shallowRef, triggerRef } from "@vue/reactivity";
const obj = shallowRef({ count: 1 });
// This will NOT trigger effects because shallow refs only track .value access
obj.value.count = 2;
// To trigger effects after mutating, use triggerRef
triggerRef(obj);
// This WILL trigger effects (replacing .value)
obj.value = { count: 3 };Checks if a value is a ref object.
/**
* Checks if a value is a ref object
* @param r - Value to check
* @returns True if the value is a ref
*/
function isRef<T>(r: Ref<T> | unknown): r is Ref<T>;
function isRef(r: any): r is Ref;Usage Examples:
import { ref, isRef } from "@vue/reactivity";
const count = ref(0);
const plainValue = 42;
console.log(isRef(count)); // true
console.log(isRef(plainValue)); // false
console.log(isRef({ value: 42 })); // false (not a real ref)Returns the inner value if the argument is a ref, otherwise returns the argument itself.
/**
* Returns the inner value if the argument is a ref, otherwise returns the argument
* @param ref - A ref or any value
* @returns The unwrapped value
*/
function unref<T>(ref: MaybeRef<T> | ComputedRef<T>): T;Usage Examples:
import { ref, unref } from "@vue/reactivity";
const count = ref(42);
const plainValue = 100;
console.log(unref(count)); // 42
console.log(unref(plainValue)); // 100
// Useful for functions that accept both refs and plain values
function useValue(maybeRef: MaybeRef<number>): number {
return unref(maybeRef) * 2;
}
console.log(useValue(count)); // 84
console.log(useValue(50)); // 100Normalizes values/refs/getters to values. Similar to unref but also handles getter functions.
/**
* Normalizes values/refs/getters to values
* @param source - A ref, getter function, or plain value
* @returns The resolved value
*/
function toValue<T>(source: MaybeRefOrGetter<T>): T;Usage Examples:
import { ref, toValue } from "@vue/reactivity";
const count = ref(42);
const getValue = () => 100;
const plainValue = 200;
console.log(toValue(count)); // 42
console.log(toValue(getValue)); // 100
console.log(toValue(plainValue)); // 200Normalizes values/refs/getters into refs, or creates a ref for a property on a reactive object.
/**
* Converts a value to a ref
* @param value - Value to convert to ref
* @returns A ref containing the value
*/
function toRef<T>(value: T): ToRef<T>;
/**
* Creates a ref for a property on a reactive object
* @param object - Reactive object
* @param key - Property key
* @returns A ref linked to the object property
*/
function toRef<T extends object, K extends keyof T>(object: T, key: K): ToRef<T[K]>;
/**
* Creates a ref for a property with a default value
* @param object - Reactive object
* @param key - Property key
* @param defaultValue - Default value if property is undefined
* @returns A ref linked to the object property with default
*/
function toRef<T extends object, K extends keyof T>(
object: T,
key: K,
defaultValue: T[K]
): ToRef<Exclude<T[K], undefined>>;Usage Examples:
import { reactive, toRef } from "@vue/reactivity";
const state = reactive({ count: 0, name: "Vue" });
// Create refs from reactive object properties
const countRef = toRef(state, "count");
const nameRef = toRef(state, "name");
console.log(countRef.value); // 0
countRef.value = 5; // Updates state.count
console.log(state.count); // 5
// Convert plain value to ref
const plainRef = toRef(42);
console.log(plainRef.value); // 42Converts a reactive object to a plain object where each property is a ref that maintains reactivity connection to the original object.
/**
* Converts a reactive object to refs for each property
* @param object - Reactive object to convert
* @returns Object with ref properties
*/
function toRefs<T extends object>(object: T): ToRefs<T>;Usage Examples:
import { reactive, toRefs } from "@vue/reactivity";
const state = reactive({
count: 0,
name: "Vue",
items: [1, 2, 3]
});
// Convert to refs - useful for destructuring
const { count, name, items } = toRefs(state);
console.log(count.value); // 0
count.value = 10; // Updates state.count
console.log(state.count); // 10
// Commonly used in composition functions
function useCounter() {
const state = reactive({ count: 0 });
return {
...toRefs(state),
increment: () => state.count++
};
}Creates a customized ref with explicit control over dependency tracking and updates.
/**
* Creates a customized ref with explicit control over tracking and triggering
* @param factory - Factory function that receives track and trigger callbacks
* @returns A custom ref object
*/
function customRef<T>(factory: CustomRefFactory<T>): Ref<T>;
type CustomRefFactory<T> = (
track: () => void,
trigger: () => void
) => {
get: () => T;
set: (value: T) => void;
};Usage Examples:
import { customRef } from "@vue/reactivity";
// Debounced ref that delays updates
function useDebouncedRef<T>(value: T, delay = 200) {
let timeout: number;
return customRef<T>((track, trigger) => {
return {
get() {
track(); // Track dependency
return value;
},
set(newValue: T) {
clearTimeout(timeout);
timeout = setTimeout(() => {
value = newValue;
trigger(); // Trigger updates
}, delay);
}
};
});
}
const debouncedValue = useDebouncedRef("hello");Force trigger effects that depend on a shallow ref. Used when you have made deep mutations to the inner value of a shallow ref.
/**
* Force trigger effects that depend on a shallow ref
* @param ref - The shallow ref to trigger
*/
function triggerRef(ref: Ref): void;Usage Examples:
import { shallowRef, triggerRef, effect } from "@vue/reactivity";
const obj = shallowRef({ count: 1 });
effect(() => {
console.log("Count:", obj.value.count);
});
// This won't trigger the effect (shallow ref)
obj.value.count = 2;
// Manually trigger effects after mutation
triggerRef(obj); // Now the effect runsReturns a proxy that shallowly unwraps properties that are refs, allowing direct property access without .value.
/**
* Creates a proxy that automatically unwraps ref properties
* @param objectWithRefs - Object containing ref properties
* @returns Proxy with automatic ref unwrapping
*/
function proxyRefs<T extends object>(objectWithRefs: T): ShallowUnwrapRef<T>;Usage Examples:
import { ref, proxyRefs } from "@vue/reactivity";
const refs = {
count: ref(0),
name: ref("Vue"),
plainValue: 42
};
const proxy = proxyRefs(refs);
// Access without .value
console.log(proxy.count); // 0 (unwrapped from ref)
console.log(proxy.name); // "Vue" (unwrapped from ref)
console.log(proxy.plainValue); // 42 (plain value)
// Assignment unwraps refs
proxy.count = 5; // Same as refs.count.value = 5
proxy.name = "React"; // Same as refs.name.value = "React"// Core ref types
type MaybeRef<T = any> = T | Ref<T> | ShallowRef<T> | WritableComputedRef<T>;
type MaybeRefOrGetter<T = any> = MaybeRef<T> | ComputedRef<T> | (() => T);
// Conversion types
type ToRef<T> = IfAny<T, Ref<T>, [T] extends [Ref] ? T : Ref<T>>;
type ToRefs<T = any> = {
[K in keyof T]: ToRef<T[K]>;
};
// Unwrapping types
type UnwrapRef<T> = T extends ShallowRef<infer V, unknown>
? V
: T extends Ref<infer V, unknown>
? UnwrapRefSimple<V>
: UnwrapRefSimple<T>;
type ShallowUnwrapRef<T> = {
[K in keyof T]: DistributeRef<T[K]>;
};
// Custom ref factory type
type CustomRefFactory<T> = (
track: () => void,
trigger: () => void
) => {
get: () => T;
set: (value: T) => void;
};Install with Tessl CLI
npx tessl i tessl/npm-vue--reactivity