Quản lý trạng thái loading và error

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

Khi làm việc với API, việc xử lý trạng thái tải dữ liệu (loading)lỗi (error) là rất quan trọng để đảm bảo trải nghiệm người dùng tốt. Nuxt 3 cung cấp cơ chế theo dõi tự động các trạng thái này thông qua các hook như useFetchuseAsyncData. Trong bài học này, bạn sẽ học cách hiển thị skeleton UI, thông báo lỗi rõ ràng, cũng như cách thử lại khi có lỗi xảy ra. Ngoài ra, bạn cũng sẽ thực hành tạo một component danh sách có xử lý loading và error thực tế.

Quản lý trạng thái loading và error

1. Theo dõi pending, error, data với useAsyncData

Ví dụ cơ bản:

<script setup>
const { data, pending, error } = await useAsyncData('posts', () =>
  $fetch('https://jsonplaceholder.typicode.com/posts')
)
</script>
  • pending: true khi đang gọi API.
  • error: chứa lỗi nếu có lỗi xảy ra.
  • data: kết quả trả về từ API.

2. Hiển thị UI loading và xử lý lỗi

<template>
  <div v-if="pending">Đang tải dữ liệu...</div>
  <div v-else-if="error">Lỗi: {{ error.message }}</div>
  <ul v-else>
    <li v-for="post in data" :key="post.id">{{ post.title }}</li>
  </ul>
</template>

Cải thiện với Skeleton Loader:

<div v-if="pending" class="skeleton">Đang tải dữ liệu...</div>

3. Retry khi lỗi (thử lại thủ công)

const { data, pending, error, refresh } = await useAsyncData('posts', () =>
  $fetch('/api/posts')
)
<button v-if="error" @click="refresh()">Thử lại</button>

4. Xử lý lỗi nâng cao với try-catch, createError, showError

Ví dụ trong API backend:

export default defineEventHandler(async () => {
  try {
    // logic...
  } catch (err) {
    throw createError({ statusCode: 500, statusMessage: 'Lỗi server!' })
  }
})

Ví dụ trong phía client:

try {
  const data = await $fetch('/api/something')
} catch (err) {
  showError({ statusCode: 400, statusMessage: 'Lỗi khi gọi API' })
}

5. Thực hành: Component danh sách có loading và error

<script setup>
const { data, pending, error, refresh } = await useFetch('/api/posts')
</script>

<template>
  <div v-if="pending">Đang tải...</div>
  <div v-else-if="error">
    Lỗi: {{ error.message }} <br />
    <button @click="refresh()">Thử lại</button>
  </div>
  <ul v-else>
    <li v-for="post in data" :key="post.id">{{ post.title }}</li>
  </ul>
</template>

Kết luận

Việc theo dõi và xử lý trạng thái loadingerror là yếu tố không thể thiếu trong ứng dụng thực tế. Bài học này đã giúp bạn nắm vững cách tận dụng pending, error, và refresh từ các hook như useFetch, useAsyncData. Bạn cũng đã biết cách hiển thị thông báo thân thiện với người dùng, thử lại khi có lỗi, và xử lý lỗi nâng cao bằng createErrorshowError. Những kỹ năng này sẽ giúp bạn xây dựng giao diện thân thiện và chuyên nghiệp hơn.

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ệ