Belajar Nuxt - Data Fetching & Server Actions
Episode 6 of 24

Belajar Nuxt - Data Fetching & Server Actions

Episode ini membahas pengambilan data di Nuxt: useAsyncData dan useFetch, composables sisi server, server actions untuk pemrosesan form, perbedaan fetch di server dan client, serta caching, revalidasi, dan suspense.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Sebuah aplikasi toko tidak berguna tanpa data. Episode 6 membahas jantung Nuxt: cara mengambil dan mengirim data. Nuxt menyediakan composables bawaan seperti useFetch dan useAsyncData yang bekerja sama dengan SSR — data diambil di server, di-embed ke halaman, lalu di-reuse di client tanpa request ganda.

Selain membaca data, episode ini juga memperkenalkan server actions: fungsi yang berjalan di server tetapi dipanggil seolah-olah fungsi biasa dari client. Ini mengubah cara kita memproses form dan mutasi data — tanpa perlu menulis endpoint HTTP secara eksplisit untuk setiap operasi.

useFetch dan useAsyncData

useFetch untuk Request Sederhana

Cara paling umum mengambil data adalah useFetch. Karena composable ini auto-import, kalian bisa langsung memakainya di komponen:

JSFetch daftar produk
const { data: produk, pending, error } = await useFetch("/api/produk")

useFetch("/api/produk") bekerja seperti fetch biasa, tapi hasilnya dirender di server saat SSR, di-embed ke payload, lalu di-reuse di client. Objek pending dan error membantu menampilkan status loading dan kegagalan di template.

useAsyncData untuk Sumber Data Lain

Jika data berasal dari fungsi JavaScript atau panggilan API eksternal, gunakan useAsyncData:

JSuseAsyncData dengan sumber custom
const { data: total } = await useAsyncData("total-produk", () => {
  return $fetch("/api/produk/total")
})

useAsyncData menerima kunci unik dan sebuah fungsi yang mengembalikan data. Kunci tersebut menjadi identitas cache — dua pemakaian dengan kunci yang sama berbagi data yang sama. $fetch adalah wrapper Nuxt di atas fetch standar dengan fitur parsing dan error handling.

Server-Side Composables

Data Hanya Tersedia di Server

Nuxt punya komposisi yang disediakan hanya untuk sisi server, biasanya dipakai di server routes. Contoh: useSession untuk membaca sesi, atau fungsi database di server/utils. Kode seperti ini tidak boleh bocor ke client.

JSserver/utils/produk.ts
export async function getProdukPopuler() {
  const items = await queryDatabase("SELECT * FROM produk LIMIT 5")
  return items
}

Fungsi queryDatabase di atas hanya ilustrasi — yang penting: apa pun yang hanya dibutuhkan server, simpan di server/utils agar tidak pernah dikirim ke browser.

Server Actions dan Form Handling

Mendefinisikan Server Action

Server actions adalah fungsi yang diekspor dari server/utils menggunakan defineServerAction. Fungsi ini bisa dipanggil langsung dari komponen, dan eksekusinya terjadi di server:

JSserver/utils/produk.ts
export const tambahProduk = defineServerAction(
  async (data: { nama: string; harga: number }) => {
    const id = await simpanKeDatabase(data)
    return { id }
  }
)

defineServerAction(async (data) => {...}) menghasilkan fungsi yang dipanggil dari client, menjalankan kode di server, lalu mengembalikan hasil. Keamanannya penting: validasi ulang input di sisi server, jangan pernah percaya data client.

Memanggil Server Action dari Komponen

JSMemanggil server action
import { tambahProduk } from "~/server/utils/produk"
 
async function submit() {
  const hasil = await tambahProduk({
    nama: form.nama,
    harga: form.harga,
  })
}

Pola ini membuat pemrosesan form sangat rapi: tidak ada URL endpoint, tidak ada serialisasi manual. Server action menjadi satu-satunya tempat logika bisnis berjalan.

Fetch Server vs Client

Perbedaan Waktu Eksekusi

useFetch berjalan di server saat halaman dirender, lalu di client saat hydration. Ini artinya data sudah tersedia di HTML pertama — bagus untuk SEO dan waktu tampil. Namun untuk data yang harus selalu segar di client, misalnya notifikasi real-time, sebaiknya pakai $fetch langsung di event handler atau composable yang hanya berjalan di client.

JSFetch murni client-side
const daftar = ref([])
 
async function muatData() {
  daftar.value = await $fetch("/api/notifikasi")
}

$fetch di dalam fungsi biasa berjalan hanya saat dipanggil — di browser. Bedakan jelas: useFetch untuk data halaman yang ikut SSR, $fetch untuk aksi interaktif.

Caching, Revalidasi, dan Suspense

Kunci Cache dan Revalidasi

Nuxt secara otomatis menyimpan hasil useAsyncData dan useFetch dalam payload SSR sehingga client tidak mengulang request. Untuk memvalidasi ulang data setelah mutasi, gunakan refresh atau clearNuxtData:

JSRevalidasi data
const { data, refresh } = await useFetch("/api/produk")
 
async function hapusProduk(id) {
  await $fetch(`/api/produk/${id}`, { method: "DELETE" })
  await refresh()
}

Panggil refresh() setelah data berubah agar tampilan mengikuti data terbaru tanpa reload halaman.

Suspense untuk Keadaan Loading

useAsyncData dan useFetch mengembalikan status pending yang bisa dipakai untuk menampilkan loading state:

HTMLLoading state di template
<template>
  <div>
    <p v-if="pending">Memuat data...</p>
    <p v-else-if="error">Gagal memuat data</p>
    <div v-else>
      <KartuProduk v-for="item in produk" :key="item.id" v-bind="item" />
    </div>
  </div>
</template>

Pola v-if pending, v-else-if error, dan v-else di atas adalah pola standar untuk menangani tiga kondisi data dalam Nuxt.

Penutup

Episode 6 membuka pintu data: useFetch dan useAsyncData untuk mengambil data yang ikut dirender di server, server actions untuk memproses mutasi dengan aman, pemahaman perbedaan fetch server dan client, serta mekanisme caching, revalidasi, dan suspense untuk pengalaman loading yang baik.

Inti yang harus dibawa pulang:

  • useFetch dan useAsyncData mengambil data di server lalu me-reuse di client.
  • Kunci pada useAsyncData menjadi identitas cache untuk berbagi data.
  • Server actions didefinisikan dengan defineServerAction dan dieksekusi di server.
  • Validasi ulang semua input di sisi server, jangan percaya data dari client.
  • $fetch dipakai untuk aksi interaktif client; useFetch untuk data halaman.
  • Gunakan refresh dan clearNuxtData untuk revalidasi setelah mutasi.

Di episode 7 selanjutnya kita akan membahas state management — mengelola state global dengan Pinia, mendefinisikan stores, menangani hydration state di SSR, dan pola Composition API untuk shared state. Keranjang belanja toko kalian akan punya rumah yang tepat.

Belajar Nuxt - Data Fetching & Server Actions | Belajar Nuxt