Episode ini membahas pengambilan data di aplikasi Vue: memakai fetch dan Axios, mengelola loading state dan error handling, pattern fetching dengan Composition API dan composables, serta integrasi Vue Query (TanStack Query) untuk caching dan synchronizing state server.

Hampir semua aplikasi nyata mengambil data dari server: daftar produk, profil user, notifikasi. Di sinilah antarmuka menjadi asynchronous — dan kesalahan yang paling umum bukan di logika data, melainkan di cara loading dan error ditangani.
Episode 8 membahas pengambilan data dengan fetch dan Axios, menata loading state dan error handling, merancang pattern fetching dengan Composition API, lalu mengenalkan Vue Query (TanStack Query) untuk caching dan sinkronisasi state server. Setelah episode ini, kalian bisa membangun UI yang memuat data dengan percaya diri dan elegan.
fetch tersedia di semua browser modern tanpa dependency tambahan:
async function ambilProduk() {
const res = await fetch("/api/produk");
if (!res.ok) {
throw new Error("Gagal memuat produk");
}
return res.json();
}fetch("/api/produk") mengembalikan promise; res.ok menandai respons HTTP sukses, dan res.json() mengurai body menjadi JavaScript object. Selalu periksa res.ok karena fetch tidak melempar error pada status 4xx/5xx.
Axios menawarkan interceptor, timeout, dan konversi JSON otomatis:
npm install axiosimport axios from "axios";
const { data } = await axios.get("/api/produk", { timeout: 5000 });axios.get("/api/produk", { timeout: 5000 }) melempar error otomatis pada status selain 2xx dan mengurai JSON langsung ke data. Gunakan Axios ketika kalian butuh interceptor untuk auth header atau logging — akan kita pakai di episode 12 dan 13.
Setiap operasi fetching punya tiga kondisi: memuat, sukses, dan error. Kelola ketiganya secara eksplisit:
<script setup>
import { ref } from "vue";
const data = ref(null);
const loading = ref(true);
const error = ref(null);
async function muat() {
loading.value = true;
error.value = null;
try {
const res = await fetch("/api/produk");
if (!res.ok) throw new Error("Server error");
data.value = await res.json();
} catch (e) {
error.value = e.message;
} finally {
loading.value = false;
}
}
muat();
</script>
<template>
<div v-if="loading">Memuat data...</div>
<div v-else-if="error">Terjadi error: {{ error }}</div>
<ul v-else>
<li v-for="item in data" :key="item.id">{{ item.nama }}</li>
</ul>
</template>v-if="loading", v-else-if="error", dan v-else menyajikan tiga kondisi tanpa membingungkan. finally memastikan loading selalu dimatikan, bahkan saat error.
Agar logika fetching bisa dipakai ulang, bungkus ke dalam composable useFetch:
import { ref } from "vue";
export function useFetch(url) {
const data = ref(null);
const loading = ref(true);
const error = ref(null);
async function jalankan() {
try {
const res = await fetch(url);
data.value = await res.json();
} catch (e) {
error.value = e.message;
} finally {
loading.value = false;
}
}
jalankan();
return { data, loading, error, jalankan };
}useFetch("/api/produk") langsung menjalankan fetching saat dipanggil di setup, dan mengembalikan tiga ref plus fungsi untuk memuat ulang. Komponen tinggal mengonsumsi hasilnya — pola ini yang menjadi fondasi integrasi TanStack Query.
Vue Query, yang kini bernama TanStack Query, mengelola state server dengan cache, retry, dan invalidasi otomatis:
npm install @tanstack/vue-queryimport { useQuery } from "@tanstack/vue-query";
const { data, isPending, isError, error, refetch } = useQuery({
queryKey: ["produk"],
queryFn: () => fetch("/api/produk").then((r) => r.json()),
});useQuery({ queryKey: ["produk"], queryFn: ... }) mengambil data, menyimpannya di cache dengan key ["produk"], dan otomatis menyediakan isPending, isError, error, serta refetch. Query yang sama tidak di-fetch ulang tanpa perlu — itulah caching yang kalian dapatkan gratis.
Saat data berubah, beri tahu TanStack Query untuk mengambil ulang:
import { useQueryClient } from "@tanstack/vue-query";
const queryClient = useQueryClient();
async function simpan(data) {
await fetch("/api/produk", { method: "POST", body: JSON.stringify(data) });
queryClient.invalidateQueries({ queryKey: ["produk"] });
}queryClient.invalidateQueries({ queryKey: ["produk"] }) menandai cache lama dan memicu fetching ulang di semua komponen yang memakai query tersebut. Ini menggantikan sinkronisasi manual antar komponen — akan kita dalami lagi di episode 14.
Tip
Gunakan TanStack Query untuk semua state yang berasal dari server, dan jaga state lokal yang benar-benar UI seperti modal terbuka atau form di dalam ref dan composables.
Episode 8 membekali kalian pengambilan data yang benar: fetch dan Axios untuk klien HTTP, state tiga kondisi untuk loading dan error handling, composable useFetch untuk reusability, serta TanStack Query untuk caching dan invalidasi state server.
Inti yang harus dibawa pulang:
res.ok saat memakai fetch.finally memastikan loading dimatikan apa pun hasilnya.useFetch membuat fetching bisa dipakai ulang.Di episode 9 selanjutnya kita membahas routing dan navigation — Vue Router untuk mengatur rute dan komponen, dynamic dan nested routes dengan lazy loading, scroll behavior dan programmatic navigation, serta route meta untuk per-route authentication.