Reactive State và Composition API
Trong bài học này, chúng ta sẽ đi sâu hơn vào cách quản lý trạng thái (state) trong Nuxt bằng cách so sánh giữa useState
và Pinia, đồng thời tìm hiểu cách kết hợp reactive state với Composition API để tạo ra các composable tái sử dụng. Học viên sẽ được thực hành tạo một composable quản lý toast hoặc modal dùng chung cho toàn bộ ứng dụng – một kỹ thuật rất thường gặp trong các dự án lớn.

Reactive State và Composition API
1. So sánh useState()
và Pinia
Tiêu chí | useState() |
Pinia |
---|---|---|
Phạm vi | Cục bộ (global trong app Nuxt) | Toàn cục (global, chia module) |
Sử dụng | Đơn giản, phù hợp cho trạng thái nhỏ | Dùng cho quản lý logic phức tạp |
Hỗ trợ DevTools | Có | Có, hỗ trợ tốt hơn với Vue DevTools |
Reactive | Có (ref ) |
Có (ref , reactive ) |
Khi nào dùng useState
?
- Khi cần chia sẻ state đơn giản giữa vài component
- Ví dụ: toggle dark mode, theme hiện tại, menu mở/đóng
Khi nào dùng Pinia?
- Khi cần state toàn cục với nhiều logic (auth, cart, user)
- Khi cần actions, getters, modules
2. Tích hợp state vào Composable tái sử dụng
Nuxt khuyến khích tạo composable chứa logic dùng chung để tái sử dụng giữa nhiều component.
Ví dụ: useModal.ts
– quản lý mở/đóng modal
export const useModal = () => {
const isOpen = useState('modal-open', () => false)
const open = () => isOpen.value = true
const close = () => isOpen.value = false
const toggle = () => isOpen.value = !isOpen.value
return { isOpen, open, close, toggle }
}
Sử dụng trong component:
<script setup>
const { isOpen, open, close } = useModal()
</script>
<template>
<button @click="open">Mở Modal</button>
<div v-if="isOpen">Đây là modal <button @click="close">Đóng</button></div>
</template>
3. Demo: Tạo Composable xử lý Toast
Tạo file: composables/useToast.ts
export const useToast = () => {
const toasts = useState('toasts', () => [])
const show = (message, type = 'info') => {
const id = Date.now()
toasts.value.push({ id, message, type })
setTimeout(() => remove(id), 3000)
}
const remove = (id) => {
toasts.value = toasts.value.filter(t => t.id !== id)
}
return { toasts, show, remove }
}
Sử dụng trong layout hoặc component chính:
<script setup>
const { toasts } = useToast()
</script>
<template>
<div class="toast-wrapper">
<div v-for="toast in toasts" :key="toast.id" :class="['toast', toast.type]">
{{ toast.message }}
</div>
</div>
</template>
Thêm nút kích hoạt toast:
<script setup>
const { show } = useToast()
</script>
<template>
<button @click="show('Lưu thành công', 'success')">Hiện thông báo</button>
</template>
Kết luận
Qua bài học này, bạn đã nắm được:
- Khi nào nên dùng
useState
, khi nào nên dùng Pinia - Cách tạo các composable quản lý state có thể tái sử dụng
- Demo thực tế với
useModal
vàuseToast
– kỹ thuật thường dùng trong ứng dụng lớn
Trong phần kế tiếp, chúng ta sẽ khám phá cách render phía server, tối ưu SEO và caching – điểm mạnh nhất của Nuxt.

Với hơn 10 năm kinh nghiệm lập trình web và từng làm việc với nhiều framework, ngôn ngữ như PHP, JavaScript, React, jQuery, CSS, HTML, CakePHP, Laravel..., tôi hy vọng những kiến thức được chia sẻ tại đây sẽ hữu ích và thiết thực cho các bạn.
Xem thêm

Chào, tôi là Vũ. Đây là blog hướng dẫn lập trình của tôi.
Liên hệ công việc qua email dưới đây.
lhvuctu@gmail.com