Master Vue 3 Composition API with TypeScript, composables, and reactive state management.
# Vue 3 Composition API Best Practices
Master Vue 3 Composition API with Google Antigravity IDE. This comprehensive guide covers composables, reactivity patterns, and state management for modern Vue applications.
## Why Composition API?
Composition API provides better logic organization and TypeScript support. Google Antigravity IDE's Gemini 3 engine suggests optimal composable patterns and reactive structures.
## Composable Patterns
```typescript
// composables/useAsync.ts
import { ref, Ref, UnwrapRef } from "vue";
interface UseAsyncReturn<T> {
data: Ref<T | null>;
error: Ref<Error | null>;
loading: Ref<boolean>;
execute: () => Promise<void>;
}
export function useAsync<T>(
asyncFn: () => Promise<T>,
immediate = true
): UseAsyncReturn<T> {
const data = ref<T | null>(null) as Ref<T | null>;
const error = ref<Error | null>(null);
const loading = ref(false);
async function execute() {
loading.value = true;
error.value = null;
try {
data.value = await asyncFn() as UnwrapRef<T>;
} catch (e) {
error.value = e instanceof Error ? e : new Error(String(e));
} finally {
loading.value = false;
}
}
if (immediate) {
execute();
}
return { data, error, loading, execute };
}
// Usage
const { data: users, loading, error, execute: refresh } = useAsync(
() => fetch("/api/users").then((r) => r.json())
);
```
## Reactive State Management
```typescript
// composables/useStore.ts
import { reactive, readonly, DeepReadonly } from "vue";
interface User {
id: string;
name: string;
email: string;
}
interface State {
user: User | null;
isAuthenticated: boolean;
theme: "light" | "dark";
}
const state = reactive<State>({
user: null,
isAuthenticated: false,
theme: "light",
});
export function useStore() {
// Actions
function login(user: User) {
state.user = user;
state.isAuthenticated = true;
}
function logout() {
state.user = null;
state.isAuthenticated = false;
}
function toggleTheme() {
state.theme = state.theme === "light" ? "dark" : "light";
}
// Return readonly state with actions
return {
state: readonly(state) as DeepReadonly<State>,
login,
logout,
toggleTheme,
};
}
```
## Form Handling Composable
```typescript
// composables/useForm.ts
import { reactive, computed, ComputedRef } from "vue";
interface FormField<T> {
value: T;
error: string | null;
touched: boolean;
}
interface UseFormReturn<T extends Record<string, unknown>> {
fields: { [K in keyof T]: FormField<T[K]> };
values: ComputedRef<T>;
errors: ComputedRef<Partial<Record<keyof T, string>>>;
isValid: ComputedRef<boolean>;
validate: () => boolean;
reset: () => void;
setFieldValue: <K extends keyof T>(field: K, value: T[K]) => void;
}
export function useForm<T extends Record<string, unknown>>(
initialValues: T,
validators: Partial<Record<keyof T, (value: unknown) => string | null>> = {}
): UseFormReturn<T> {
const fields = reactive(
Object.fromEntries(
Object.entries(initialValues).map(([key, value]) => [
key,
{ value, error: null, touched: false },
])
)
) as { [K in keyof T]: FormField<T[K]> };
const values = computed(() =>
Object.fromEntries(
Object.entries(fields).map(([key, field]) => [key, field.value])
) as T
);
const errors = computed(() =>
Object.fromEntries(
Object.entries(fields)
.filter(([, field]) => field.error)
.map(([key, field]) => [key, field.error])
) as Partial<Record<keyof T, string>>
);
const isValid = computed(() =>
Object.values(fields).every((field) => !field.error)
);
function validate(): boolean {
let valid = true;
for (const [key, field] of Object.entries(fields)) {
const validator = validators[key as keyof T];
if (validator) {
const error = validator(field.value);
field.error = error;
field.touched = true;
if (error) valid = false;
}
}
return valid;
}
function reset() {
for (const [key, value] of Object.entries(initialValues)) {
fields[key as keyof T].value = value as T[keyof T];
fields[key as keyof T].error = null;
fields[key as keyof T].touched = false;
}
}
function setFieldValue<K extends keyof T>(field: K, value: T[K]) {
fields[field].value = value;
fields[field].touched = true;
const validator = validators[field];
if (validator) {
fields[field].error = validator(value);
}
}
return { fields, values, errors, isValid, validate, reset, setFieldValue };
}
```
## Lifecycle Composable
```typescript
// composables/useMounted.ts
import { ref, onMounted, onUnmounted } from "vue";
export function useMounted() {
const isMounted = ref(false);
onMounted(() => {
isMounted.value = true;
});
onUnmounted(() => {
isMounted.value = false;
});
return isMounted;
}
// composables/useEventListener.ts
import { onMounted, onUnmounted } from "vue";
export function useEventListener<K extends keyof WindowEventMap>(
target: Window | Element,
event: K,
handler: (event: WindowEventMap[K]) => void
) {
onMounted(() => {
target.addEventListener(event, handler as EventListener);
});
onUnmounted(() => {
target.removeEventListener(event, handler as EventListener);
});
}
```
## Best Practices
- Extract reusable logic into composables
- Use ref for primitives, reactive for objects
- Apply readonly for exposed state
- Implement proper cleanup in onUnmounted
- Use computed for derived state
- Keep composables focused and testable
Google Antigravity IDE provides Vue 3 composable templates and automatically suggests optimal reactive patterns for your applications.This Vue.js prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their vue.js implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For Vue.js projects, consider mentioning your framework version, coding style, and any specific libraries you're using.