Functions That Use Reactivity
Composables — Reusable Logic
A composable is a function (prefixed `use`) that wraps reactive state and reusable logic — Vue's answer to mixins and React hooks.
What you'll learn
- Write useCounter
- Compose composables
- Pass refs into a composable
A composable is a function that uses Vue’s reactivity APIs (ref, computed, watch, lifecycle hooks) and returns reactive values. The convention is to prefix them with use. They are Vue’s idiomatic way to share stateful logic.
A First Composable — useCounter
// composables/useCounter.ts
import { ref } from 'vue'
export function useCounter(initial = 0) {
const count = ref(initial)
const inc = () => count.value++
const dec = () => count.value--
const reset = () => count.value = initial
return { count, inc, dec, reset }
} <script setup lang="ts">
import { useCounter } from './composables/useCounter'
const { count, inc, dec } = useCounter(10)
</script>
<template>
<button @click="dec">-</button>
<span>{{ count }}</span>
<button @click="inc">+</button>
</template> Side Effects & Cleanup
Composables can register lifecycle hooks. The hooks register on the consuming component — so cleanup happens automatically.
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
const x = ref(0)
const y = ref(0)
const update = (e: MouseEvent) => { x.value = e.pageX; y.value = e.pageY }
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
return { x, y }
} Composing Composables
A composable can call other composables — that’s how complex logic stays small.
export function useUser(id: Ref<number>) {
const { data, isLoading } = useFetch(() => `/api/users/${id.value}`)
const isAdmin = computed(() => data.value?.role === 'admin')
return { user: data, isLoading, isAdmin }
} Accept Refs as Inputs
So callers can change inputs reactively, accept refs (or use MaybeRef<T> and toValue for flexibility).
import { toValue, watchEffect, type MaybeRefOrGetter } from 'vue'
export function useFetch(url: MaybeRefOrGetter<string>) {
const data = ref<unknown>(null)
watchEffect(async () => {
const res = await fetch(toValue(url))
data.value = await res.json()
})
return { data }
} The community ships a giant collection of these in VueUse — a great reference.
provide & inject — Dependency Injection →