VueUse 완벽 가이드 | Vue Composables·유틸리티·Hooks·실전 활용
이 글의 핵심
VueUse로 Vue 개발을 가속화하는 완벽 가이드입니다. 200+ Composables, useFetch, useLocalStorage, useMouse까지 실전 예제로 정리했습니다.
실무 경험 공유: 직접 구현한 Composables를 VueUse로 대체하면서, 개발 시간이 50% 단축되고 코드 품질이 향상된 경험을 공유합니다.
들어가며: “반복 코드가 많아요”
실무 문제 시나리오
시나리오 1: 같은 로직을 반복해요
fetch, localStorage 등을 매번 구현합니다. VueUse는 200+ Composables를 제공합니다.
시나리오 2: 브라우저 API가 복잡해요
Native API는 어렵습니다. VueUse는 간단한 래퍼를 제공합니다.
시나리오 3: 반응형 유틸리티가 필요해요
직접 만들기 어렵습니다. VueUse는 즉시 사용 가능합니다.
1. VueUse란?
핵심 특징
VueUse는 Vue Composables 컬렉션입니다.
주요 장점:
- 200+ Composables: 다양한 유틸리티
- TypeScript: 완벽한 지원
- Tree-shakable: 필요한 것만
- SSR 친화적: Nuxt 호환
- 잘 테스트됨: 안정적
2. 설치 및 기본 사용
설치
npm install @vueuse/core
기본 사용
<script setup lang="ts">
import { useMouse, useLocalStorage } from '@vueuse/core';
const { x, y } = useMouse();
const count = useLocalStorage('count', 0);
</script>
<template>
<div>
<p>Mouse: {{ x }}, {{ y }}</p>
<p>Count: {{ count }}</p>
<button @click="count++">Increment</button>
</div>
</template>
3. State Composables
useLocalStorage
<script setup lang="ts">
import { useLocalStorage } from '@vueuse/core';
const user = useLocalStorage('user', { name: '', email: '' });
</script>
<template>
<input v-model="user.name" placeholder="Name" />
<input v-model="user.email" placeholder="Email" />
</template>
useSessionStorage
<script setup lang="ts">
import { useSessionStorage } from '@vueuse/core';
const token = useSessionStorage('token', '');
</script>
4. Browser Composables
useFetch
<script setup lang="ts">
import { useFetch } from '@vueuse/core';
const { data, error, isFetching } = useFetch('/api/users').json();
</script>
<template>
<div v-if="isFetching">Loading...</div>
<div v-else-if="error">Error: {{ error }}</div>
<ul v-else>
<li v-for="user in data" :key="user.id">{{ user.name }}</li>
</ul>
</template>
useClipboard
<script setup lang="ts">
import { useClipboard } from '@vueuse/core';
const { text, copy, copied } = useClipboard();
const handleCopy = () => {
copy('Hello VueUse!');
};
</script>
<template>
<button @click="handleCopy">
{{ copied ? 'Copied!' : 'Copy' }}
</button>
<p>Clipboard: {{ text }}</p>
</template>
5. Sensors Composables
useMouse
<script setup lang="ts">
import { useMouse } from '@vueuse/core';
const { x, y } = useMouse();
</script>
<template>
<div>Mouse: {{ x }}, {{ y }}</div>
</template>
useScroll
<script setup lang="ts">
import { useScroll } from '@vueuse/core';
import { ref } from 'vue';
const el = ref<HTMLElement>();
const { x, y, isScrolling, arrivedState } = useScroll(el);
</script>
<template>
<div ref="el" style="height: 300px; overflow: auto;">
<div style="height: 1000px;">
<p>Scroll Y: {{ y }}</p>
<p>Is Scrolling: {{ isScrolling }}</p>
<p>At Top: {{ arrivedState.top }}</p>
<p>At Bottom: {{ arrivedState.bottom }}</p>
</div>
</div>
</template>
6. Elements Composables
useIntersectionObserver
<script setup lang="ts">
import { useIntersectionObserver } from '@vueuse/core';
import { ref } from 'vue';
const target = ref<HTMLElement>();
const isVisible = ref(false);
useIntersectionObserver(target, ([{ isIntersecting }]) => {
isVisible.value = isIntersecting;
});
</script>
<template>
<div ref="target">
<p v-if="isVisible">I'm visible!</p>
</div>
</template>
useElementSize
<script setup lang="ts">
import { useElementSize } from '@vueuse/core';
import { ref } from 'vue';
const el = ref<HTMLElement>();
const { width, height } = useElementSize(el);
</script>
<template>
<div ref="el">
Size: {{ width }} x {{ height }}
</div>
</template>
7. Utilities
useDebounce
<script setup lang="ts">
import { ref } from 'vue';
import { useDebounceFn } from '@vueuse/core';
const search = ref('');
const results = ref([]);
const debouncedSearch = useDebounceFn(async () => {
const response = await fetch(`/api/search?q=${search.value}`);
results.value = await response.json();
}, 500);
</script>
<template>
<input v-model="search" @input="debouncedSearch" />
<ul>
<li v-for="result in results" :key="result.id">{{ result.name }}</li>
</ul>
</template>
useToggle
<script setup lang="ts">
import { useToggle } from '@vueuse/core';
const [isOpen, toggle] = useToggle();
</script>
<template>
<button @click="toggle()">Toggle</button>
<div v-if="isOpen">Content</div>
</template>
8. 실전 예제: 다크 모드
<script setup lang="ts">
import { useDark, useToggle } from '@vueuse/core';
const isDark = useDark();
const toggleDark = useToggle(isDark);
</script>
<template>
<button @click="toggleDark()">
{{ isDark ? '🌙' : '☀️' }}
</button>
</template>
정리 및 체크리스트
핵심 요약
- VueUse: Vue Composables 컬렉션
- 200+ Composables: 다양한 유틸리티
- TypeScript: 완벽한 지원
- Tree-shakable: 필요한 것만
- SSR 친화적: Nuxt 호환
- 잘 테스트됨: 안정적
구현 체크리스트
- VueUse 설치
- State Composables 사용
- Browser Composables 사용
- Sensors Composables 사용
- Elements Composables 사용
- Utilities 활용
- 커스텀 Composable 작성
같이 보면 좋은 글
- Vue 3 Composition API 가이드
- Pinia 완벽 가이드
- Nuxt 3 완벽 가이드
이 글에서 다루는 키워드
VueUse, Vue 3, Composables, Hooks, Utilities, Frontend, TypeScript
자주 묻는 질문 (FAQ)
Q. React Hooks와 비슷한가요?
A. 네, 개념은 비슷하지만 Vue Composition API에 최적화되어 있습니다.
Q. Nuxt에서 사용할 수 있나요?
A. 네, Nuxt 3에서 완벽하게 작동합니다.
Q. 번들 크기는 어떤가요?
A. Tree-shakable이라 사용한 것만 포함됩니다.
Q. 프로덕션에서 사용해도 되나요?
A. 네, 많은 Vue 프로젝트에서 안정적으로 사용하고 있습니다.