Data Fetching dan API Client
Teknik mengambil dan mengelola data dari server di aplikasi frontend
Data fetching adalah proses aplikasi frontend mengambil data dari server melalui HTTP request.
Fetch API Native
Browser modern memiliki fetch built-in.
async function getUsers() {
const response = await fetch("/api/users");
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}Abort Request
const controller = new AbortController();
fetch("/api/users", { signal: controller.signal })
.then((res) => res.json())
.catch((err) => {
if (err.name === "AbortError") {
console.log("Request dibatalkan");
}
});
// Batalkan saat komponen unmount atau request baru
timeout(() => controller.abort(), 5000);React Query / TanStack Query
Library standar industri untuk server state management.
import { useQuery, useMutation, QueryClient } from "@tanstack/react-query";
const queryClient = new QueryClient();
function Users() {
const { data, isLoading, error } = useQuery({
queryKey: ["users"],
queryFn: getUsers,
staleTime: 5 * 60 * 1000, // data dianggap fresh 5 menit
});
if (isLoading) return <Spinner />;
if (error) return <Error message={error.message} />;
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
// Mutation dengan invalidasi cache
const mutation = useMutation({
mutationFn: createUser,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["users"] });
},
});Fitur kunci: caching, background refetch, deduplication, optimistic updates, pagination.
SWR
Alternatif ringan dari Vercel.
import useSWR from "swr";
function Profile() {
const { data, error, isLoading } = useSWR("/api/user", fetcher, {
refreshInterval: 3000,
revalidateOnFocus: true,
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error</div>;
return <div>Hello, {data.name}</div>;
}GraphQL dengan Relay / Apollo
Apollo Client
import { ApolloClient, InMemoryCache, gql } from "@apollo/client";
const client = new ApolloClient({
uri: "/graphql",
cache: new InMemoryCache(),
});
const GET_USERS = gql`
query GetUsers {
users {
id
name
}
}
`;
function Users() {
const { loading, error, data } = useQuery(GET_USERS);
// ...
}Keunggulan GraphQL: fetch hanya field yang dibutuhkan, single endpoint, strong typing.
Server Actions (Next.js)
"use server";
async function createUser(formData) {
const name = formData.get("name");
await db.user.create({ data: { name } });
revalidatePath("/users");
}<form action={createUser}>
<input name="name" />
<button type="submit">Create</button>
</form>Pola Terbaik
- Deklarasikan query key dengan struktur yang predictable:
["users", { page, filter }] - Pisahkan data fetching dari UI — custom hooks seperti
useUsers() - Handle loading dan error state di setiap fetch
- Gunakan pagination untuk list besar: cursor-based lebih scalable dari offset
- Optimistic update untuk UX responsif: update UI dulu, rollback jika gagal