A composable is a function that uses the Composition API to encapsulate and reuse stateful logic. They are the Vue 3 equivalent of React custom hooks.
// src/composables/useFetch.js
import { ref } from 'vue'
export function useFetch(url) {
const data = ref(null)
const loading = ref(true)
const error = ref(null)
fetch(url)
.then(r => r.json())
.then(d => { data.value = d })
.catch(e => { error.value = e.message })
.finally(() => { loading.value = false })
return { data, loading, error }
}
<script setup>
import { useFetch } from '@/composables/useFetch'
const { data: users, loading, error } = useFetch('/api/users')
</script>
<template>
<div v-if="loading">Loading...</div>
<ul v-else>
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
</ul>
</template>
// src/composables/useLocalStorage.js
import { ref, watch } from 'vue'
export function useLocalStorage(key, initialValue) {
const stored = localStorage.getItem(key)
const value = ref(stored ? JSON.parse(stored) : initialValue)
watch(value, (newVal) => {
localStorage.setItem(key, JSON.stringify(newVal))
}, { deep: true })
return value
}
// Usage
const theme = useLocalStorage('theme', 'light')
theme.value = 'dark' // automatically persisted