Recraftory

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