+11

Data fetching trong Nuxt 3 (phần 1)

Nuxt 3 đã ra mắt được khoảng và tháng rồi. Nhưng với nhiều anh em lập trình viên web chắc hẳn chưa có cơ hội hoặc vẫn còn nhiều nghi ngại chưa muốn áp dụng cho dự án của mình. Trong khoảng thời gian áp dụng nuxt 3 vào dự án mình nhận thấy nuxt 3 thật sự có rất nhiều ưu điểm. Trong bài viết này mình muốn giới thiệu với mọi người một khái niệm, công cụ đã có trong nuxt 2 nhưng đã được thay đổi, cải tiến trong nuxt 3. Đó là data fetching. Data fetching trong nuxt 3 bao gồm: useAsyncData, useLazyAsyncData, useFetch, useLazyFetch. Trong phạm vi phần một này mình sẽ nói về hai công cụ thường được sử dụng nhất đó là useAsyncData và useFetch.

1. useFetch

useFetch được render ở server side(trong mode server side rendering của nuxt) và được sử dụng để nạp dữ liệu vào trong ứng dụng nuxt của bạn. useFetch có thể được sử dụng ở cả page, các component hay các plugin. Cách sử dụng của useFetch rất đơn giản như dưới đây:

<script setup>
const { data: count } = await useFetch('/api/count')
</script>
<template>
  Page visits: {{ count }}
</template>

Đây là cách dùng cơ bản và đơn giản nhất của useFetch, chúng ta chỉ cần truyền url vào trong useFetch và việc chúng ta là chờ đợi kết quả trả về. Cách dùng này khá bất tiện vì mỗi lần gọi api ta lại phải truyền một URL dài ngoằng vào useFetch và nếu URL này được sử dụng ở nhiều nơi thì khá khó quản lý. Thường anh em chắc sẽ tạo một thư mục api và viết các hàm gọi api vào các file trong đó sau đó import vào component hoặc page phải không nào. Với cách làm này thì anh em không thể sử dụng được useFetch, nhưng không sao nuxt 3 đã cung cấp cho chúng ta một công cụ đó là useAsyncData mà mình sẽ nói ngay sau đây. Giờ thì quay lại với useFetch nào. useFetch thật ra có rất nhiều cách sử dụng tùy vào từng trường hợp. Theo docs của nhà sản xuất thì cấu trúc của useFetch nó sẽ như thế này:

function useFetch(
  url: string | Request | Ref<string | Request> | () => string | Request,
  options?: UseFetchOptions<DataT>
): Promise<AsyncData<DataT>>

type UseFetchOptions = {
  key?: string
  method?: string
  query?: SearchParams
  params?: SearchParams
  body?: RequestInit['body'] | Record<string, any>
  headers?: { key: string, value: string }[]
  baseURL?: string
  server?: boolean
  lazy?: boolean
  immediate?: boolean
  default?: () => DataT
  transform?: (input: DataT) => DataT
  pick?: string[]
  watch?: WatchSource[]
}

type AsyncData<DataT> = {
  data: Ref<DataT>
  pending: Ref<boolean>
  refresh: (opts?: { dedupe?: boolean }) => Promise<void>
  execute: () => Promise<void>
  error: Ref<Error | boolean>
}

Về cơ bản useFetch bắt buộc phải có url còn options có thể có hoặc không. Options bao gồm:

  • method: Phương thức của request.
  • query: Thêm các query cho request
  • params: Alias cho query
  • body: Request body.
  • headers: Request headers.
  • baseURL: Base URL.
  • key: một khóa duy nhất để đảm bảo rằng quá trình tìm nạp dữ liệu có thể được loại bỏ trùng lặp đúng cách giữa các yêu cầu, nếu không được cung cấp, khóa này sẽ được tạo dựa trên vị trí mã tĩnh được useAsyncData sử dụng(cái này anh em để ý vì không thêm hay bị dính cache khi mà chuyển trang do nuxt không gọi lại api. Để giải quyết vấn đề này anh em sử dụng clearNuxtData để xóa dữ liệu của key đó đi).
  • server: Có tìm nạp dữ liệu trên máy chủ hay không (mặc định là true).
  • default: Một chức năng ban đầu để đặt giá trị mặc định của dữ liệu, trước khi chức năng không đồng bộ giải quyết - đặc biệt hữu ích khi anh em để lazy là true .
  • pick: Chỉ chọn các khóa được chỉ định trong mảng này từ kết quả hàm.
  • watch: Lắng nghe sự thay đổi của đối tượng nào đó để gọi lại useFetch(cái này sử dụng để watch route query cũng khá tiện đỡ phải set watchQuery: true như nuxt 2).
  • transform: Sử dụng để transform đầu ra.
  • immediate: Khi được đặt thành false, sẽ ngăn yêu cầu kích hoạt useFetch ngay lập tức. (mặc định là true) Các giá trị mà useFetch trả về:
  • data: Dữ liệu mà useFetch gọi từ api.
  • pending: trạng thái useFetch có còn được gọi hay không(true/false).
  • refresh/execute : hàm refresh hoặc execute có thể được gọi bên ngoài useFetch sử dụng để fetch lại dữ liệu.
  • error: object error trong trường hợp gọi api bị lỗi Sau đây là một ví dụ nhỏ có sử dụng một vài options trên:
const { data, pending, error, refresh } = await useFetch('https://api.nuxtjs.dev/mountains',{
    pick: ['title'],
    query: { param1, param2: 'value2' }
})
const refreshData = () => refresh()

Cách sử dụng này sẽ trả ra title của các phần tử trong mảng trả về từ url là "https://api.nuxtjs.dev/mountains?param1=value1&param2=value2" và chúng ta có thể gọi lại useFetch thông qua hàm refreshData

2. useAsyncData

Vừa rồi mình đã nói về useFetch và có để cập qua về một sự bất tiện nhỏ của nó. Để khắc phục bất tiện này chúng ta sử dụng useAsyncData. Cách dùng của useAsyncData cũng gần tương tự như useFetch như sau:

<script setup>
const { data } = await useAsyncData('count', () => $fetch('/api/count'))
</script>
<template>
  Page visits: {{ data }}
</template>

Giả sử ta có hàm:

export const getPost = () => axios.get('/api/get-post-in-viblo')

Để sử dụng trong useAsyncData thì chúng ta chỉ cần sửa thành:

const { data } = await useAsyncData('count', () => getPost())

Về cơ bản useAsyncData khác useFetch ở điểm đó. Còn về cấu trúc thì useAsyncData và useFetch cũng khá giống nhau:

function useFetch(
  url: string | Request | Ref<string | Request> | () => string | Request,
  options?: UseFetchOptions<DataT>
): Promise<AsyncData<DataT>>
type UseFetchOptions = {
  key?: string
  method?: string
  query?: SearchParams
  params?: SearchParams
  body?: RequestInit['body'] | Record<string, any>
  headers?: { key: string, value: string }[]
  baseURL?: string
  server?: boolean
  lazy?: boolean
  immediate?: boolean
  default?: () => DataT
  transform?: (input: DataT) => DataT
  pick?: string[]
  watch?: WatchSource[]
}
type AsyncData<DataT> = {
  data: Ref<DataT>
  pending: Ref<boolean>
  refresh: (opts?: { dedupe?: boolean }) => Promise<void>
  execute: () => Promise<void>
  error: Ref<Error | boolean>
}

Các options trong useAsyncData cũng giống như trong useFetch. Có một lưu ý nhỏ khi sử dụng useAsyncData hay useFetch là anh em nhớ thêm key cho chúng và nhớ clearNuxtData nếu muốn useAsyncData hoặc useFetch được gọi lại khi chúng ta chuyển trang nhé. Ví dụ như thế này:

<script setup>
await clearNuxtData('count')
const { data } = await useAsyncData('count', () => $fetch('/api/count'))
</script>

Trên đây mình đã giới thiệu hai công cụ data fetching trong nuxt 3 là useAsyncData và useFetch. Vẫn còn useLazyAsyncData và useLazyFetch nữa mình sẽ để trong phần sau. Trong quá trình viết bài của mình khó tránh khỏi có sai sót mong nhận được sự góp ý từ mọi người. Cuối cùng cảm ơn anh em đã giành thời gian xem, hi vọng phần chia sẻ của mình sẽ giúp ích được phần nào cho anh em đang tìm hiểu về nuxt 3.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.