VueUse es una colección de composables para tareas comunes: APIs del navegador, sensores, estado, animaciones, red y más. En lugar de escribir tu propio useLocalStorage o useDebounceFn desde cero, instalas @vueuse/core y obtienes más de 200 composables probados que funcionan con el sistema de reactividad de Vue 3.
npm install @vueuse/coreComposables más útiles por categoría
Navegador y DOM
useLocalStorage / useSessionStorage: almacenamiento reactivo que se sincroniza automáticamente.
const theme = useLocalStorage('theme', 'light')
theme.value = 'dark' // guardado en localStorage inmediatamenteuseClipboard: copiar al portapapeles.
const { copy, copied } = useClipboard()
await copy('Hello!')
// copied.value es true durante 1,5 segundosuseMediaQuery: media query CSS reactiva.
const isMobile = useMediaQuery('(max-width: 768px)')useDark: modo oscuro con persistencia.
const isDark = useDark()
const toggle = useToggle(isDark)useEventListener: event listeners con limpieza automática.
useEventListener(window, 'resize', () => {
console.log(window.innerWidth)
})
// el listener se elimina automáticamente cuando el componente se desmontaEstado
useToggle: alternado booleano.
const [value, toggle] = useToggle(false)
toggle() // true
toggle() // falseuseDebounceFn / useThrottleFn: debounce y throttle.
const search = useDebounceFn((query: string) => {
fetchResults(query)
}, 300)createGlobalState: estado compartido entre componentes sin Pinia.
const useGlobalCounter = createGlobalState(() => {
const count = ref(0)
return { count }
})Red
useFetch: wrapper reactivo de fetch (distinto del useFetch de Nuxt).
const { data, error, isFetching } = useFetch('https://api.example.com/posts')
.get()
.json<Post[]>()useWebSocket: conexión WebSocket reactiva.
const { data, send, status } = useWebSocket('wss://example.com/ws')
watch(data, (message) => {
console.log('Received:', message)
})Sensores
useMouse: posición del ratón reactiva.
const { x, y } = useMouse()useIntersectionObserver: detecta la visibilidad de un elemento.
const target = ref<HTMLElement>()
const isVisible = ref(false)
useIntersectionObserver(target, ([entry]) => {
isVisible.value = entry.isIntersecting
})useElementSize: dimensiones reactivas de un elemento.
const el = ref<HTMLElement>()
const { width, height } = useElementSize(el)Utilidades
watchDebounced: watcher con debounce.
const search = ref('')
watchDebounced(search, (value) => {
fetchResults(value)
}, { debounce: 300 })whenever: watch que se ejecuta solo cuando el valor es truthy.
const isReady = ref(false)
whenever(isReady, () => {
console.log('Ready!')
})useAsyncState: ejecuta una función asíncrona con estado reactivo de carga/error.
const { state, isLoading, error } = useAsyncState(
() => fetch('/api/user').then(r => r.json()),
null // estado inicial
)Uso en un componente real
<script setup>
import { useLocalStorage, useDebounceFn, useMediaQuery } from '@vueuse/core'
const searchQuery = useLocalStorage('search', '')
const isMobile = useMediaQuery('(max-width: 768px)')
const debouncedSearch = useDebounceFn((query: string) => {
fetchResults(query)
}, 300)
watch(searchQuery, (q) => debouncedSearch(q))
</script>
<template>
<input v-model="searchQuery" :placeholder="isMobile ? 'Search...' : 'Search articles...'" />
</template>VueUse frente a escribir el tuyo propio
Escribe tu propio composable cuando la lógica es específica de tu dominio. Usa VueUse cuando el problema es genérico: debounce, almacenamiento, media queries, portapapeles, intersection observer. Los composables de VueUse gestionan casos borde, compatibilidad con SSR y limpieza que de otro modo tendrías que implementar tú mismo.