Reactive State và Composition API

Tạo bởi Hoàng Vũ, chỉnh sửa cuối lúc 19 tháng 4, 2025

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ó, 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 useModaluseToast – 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.

Website Logo

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.

Bình luận

Website Logo

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

Chúng Tôi Trên

Bạn đang muốn học về lập trình website?

Bạn cần nâng cao kiến thức chuyên nghiệp hơn để nâng cao cơ hội nghề nghiệp? Liên hệ