Provides Vue 3 Composition API compatibility for Vue 2 applications with reactive state management and lifecycle hooks.
—
Derived reactive state that automatically updates when dependencies change. Computed properties provide cached, derived values that recalculate only when their reactive dependencies change.
Creates a computed property with a getter function that automatically tracks dependencies and caches results.
/**
* Creates a read-only computed property
* @param getter - Function that computes the value
* @returns Read-only computed reference
*/
function computed<T>(getter: ComputedGetter<T>): ComputedRef<T>;
type ComputedGetter<T> = () => T;
interface ComputedRef<T = any> extends WritableComputedRef<T> {
readonly value: T;
}Usage Examples:
import { ref, computed } from "@vue/composition-api";
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
console.log(doubleCount.value); // 0
count.value = 5;
console.log(doubleCount.value); // 10
// Complex computed with multiple dependencies
const firstName = ref("John");
const lastName = ref("Doe");
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
console.log(fullName.value); // "John Doe"Creates a computed property with both getter and setter functions, allowing two-way binding and derived state manipulation.
/**
* Creates a writable computed property
* @param options - Object with get and set functions
* @returns Writable computed reference
*/
function computed<T>(options: WritableComputedOptions<T>): WritableComputedRef<T>;
interface WritableComputedOptions<T> {
get: ComputedGetter<T>;
set: ComputedSetter<T>;
}
type ComputedSetter<T> = (value: T) => void;
interface WritableComputedRef<T> extends Ref<T> {
readonly effect: ReactiveEffect<T>;
}Usage Examples:
import { ref, computed } from "@vue/composition-api";
const firstName = ref("John");
const lastName = ref("Doe");
const fullName = computed({
get: () => `${firstName.value} ${lastName.value}`,
set: (value: string) => {
const parts = value.split(" ");
firstName.value = parts[0] || "";
lastName.value = parts[1] || "";
},
});
console.log(fullName.value); // "John Doe"
// Setting the computed value updates the underlying refs
fullName.value = "Jane Smith";
console.log(firstName.value); // "Jane"
console.log(lastName.value); // "Smith"Advanced usage patterns for computed properties including conditional logic, async operations, and error handling.
Conditional Computed:
import { ref, computed } from "@vue/composition-api";
const user = ref<{ name: string; email?: string } | null>(null);
const displayName = computed(() => {
if (!user.value) return "Guest";
return user.value.email ? `${user.value.name} (${user.value.email})` : user.value.name;
});
// Computed with fallback values
const safeValue = computed(() => user.value?.name ?? "Unknown");Computed with Complex Logic:
import { ref, reactive, computed } from "@vue/composition-api";
const items = ref([
{ id: 1, name: "Apple", category: "fruit", price: 1.2 },
{ id: 2, name: "Banana", category: "fruit", price: 0.8 },
{ id: 3, name: "Carrot", category: "vegetable", price: 0.6 },
]);
const filters = reactive({
category: "",
maxPrice: null as number | null,
searchTerm: "",
});
const filteredItems = computed(() => {
return items.value.filter((item) => {
const matchesCategory = !filters.category || item.category === filters.category;
const matchesPrice = !filters.maxPrice || item.price <= filters.maxPrice;
const matchesSearch = !filters.searchTerm ||
item.name.toLowerCase().includes(filters.searchTerm.toLowerCase());
return matchesCategory && matchesPrice && matchesSearch;
});
});
const itemStats = computed(() => ({
total: filteredItems.value.length,
avgPrice: filteredItems.value.reduce((sum, item) => sum + item.price, 0) / filteredItems.value.length || 0,
categories: [...new Set(filteredItems.value.map(item => item.category))],
}));Computed with Side Effects (Anti-pattern Warning):
import { ref, computed, watch } from "@vue/composition-api";
// ❌ Don't do this - computed should be pure
const badComputed = computed(() => {
console.log("This runs on every access!"); // Side effect
return someValue.value * 2;
});
// ✅ Use watchers for side effects instead
const someValue = ref(0);
const doubledValue = computed(() => someValue.value * 2);
watch(doubledValue, (newValue) => {
console.log("Doubled value changed:", newValue);
});Computed properties are cached and only recalculate when dependencies change, making them efficient for expensive operations.
import { ref, computed } from "@vue/composition-api";
const expensiveData = ref([/* large array */]);
// This computation only runs when expensiveData changes
const processedData = computed(() => {
console.log("Processing data..."); // Only logs when dependencies change
return expensiveData.value
.filter(item => item.active)
.map(item => ({ ...item, processed: true }))
.sort((a, b) => a.priority - b.priority);
});
// Multiple accesses use the cached result
console.log(processedData.value); // Processes data
console.log(processedData.value); // Uses cache
console.log(processedData.value); // Uses cacheTypical usage patterns within Vue component setup functions.
import { defineComponent, ref, computed } from "@vue/composition-api";
export default defineComponent({
props: {
multiplier: {
type: Number,
default: 1,
},
},
setup(props) {
const baseValue = ref(10);
// Computed property using props and reactive state
const computedValue = computed(() => baseValue.value * props.multiplier);
// Computed property for template usage
const isEven = computed(() => computedValue.value % 2 === 0);
// Writable computed for v-model compatibility
const doubledBase = computed({
get: () => baseValue.value * 2,
set: (value) => {
baseValue.value = value / 2;
},
});
return {
baseValue,
computedValue,
isEven,
doubledBase,
};
},
});interface ComputedRef<T = any> extends WritableComputedRef<T> {
readonly value: T;
}
interface WritableComputedRef<T> extends Ref<T> {
readonly effect: ReactiveEffect<T>;
}
interface WritableComputedOptions<T> {
get: ComputedGetter<T>;
set: ComputedSetter<T>;
}
type ComputedGetter<T> = () => T;
type ComputedSetter<T> = (value: T) => void;
interface ReactiveEffect<T = any> {
(): T;
_isEffect: true;
id: number;
active: boolean;
raw: () => T;
deps: Array<Dep>;
options: ReactiveEffectOptions;
}
interface ReactiveEffectOptions {
lazy?: boolean;
scheduler?: (job: ReactiveEffect) => void;
onTrack?: (event: DebuggerEvent) => void;
onTrigger?: (event: DebuggerEvent) => void;
onStop?: () => void;
}Install with Tessl CLI
npx tessl i tessl/npm-vue--composition-api