CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue--reactivity

Vue.js's standalone reactivity system providing reactive references, objects, computed values, effects, and watchers with fine-grained dependency tracking.

Pending
Overview
Eval results
Files

refs.mddocs/

Reactive References

Reactive references provide fine-grained reactivity for primitive values and objects by wrapping them in a reactive container that tracks access and mutations.

Capabilities

ref()

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 reactivity

shallowRef()

Creates 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 };

isRef()

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)

unref()

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)); // 100

toValue()

Normalizes 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)); // 200

toRef()

Normalizes 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); // 42

toRefs()

Converts 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++
  };
}

customRef()

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");

triggerRef()

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 runs

proxyRefs()

Returns 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"

Types

// 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

docs

computed.md

effect-scopes.md

effects.md

index.md

reactive-objects.md

refs.md

utilities.md

watchers.md

tile.json