tutorial

85 Handling Error dan Loading State di Frontend

85 Handling Error dan Loading State di Frontend

Error handling dan loading state adalah dua hal yang tak dapat dipisahkan dari pengembangan frontend modern. Dalam rangka meningkatkan kualitas UX (user experience), baik error maupun loading perlu di-handle secara konsisten dan elegan di setiap aplikasi web atau mobile. Saya percaya, kualitas penanganan error dan loading jauh lebih fundamental daripada efek animated yang kadang hanya sebagai “hiasan”.

Pada artikel ini, saya akan membagikan 85 best practices, insight, dan snippet kode tentang bagaimana menangani error dan loading state di frontend, lengkap dengan contoh kode React, diagram alur, dan simulasi. Tujuannya: agar aplikasi kita semakin robust, aman, dan nyaman digunakan.


Mengapa Error dan Loading State Penting?

Mari mulai dengan dua pertanyaan penting:

  1. Apa jadinya jika loading tidak diindikasikan ke user?
  2. Bagaimana jika error datang tetapi tidak di-handle?

Jawabannya gampang: user akan merasa aplikasi “bengong”, atau parahnya—keluar begitu saja, meninggalkan aplikasi dan reputasi developer.

Error dan loading state bukan cuma urusan visual, tapi juga menjadi bagian dari reliability (GX — “Genuine Experience”) aplikasi kita.


Cara-cara Menangani Error dan Loading State

Berikut mantra paling dasar yang wajib dipegang:

“Selalu asumsikan API bisa fail. Selalu informasikan perubahan status ke user.”

Kita bisa breakdown tekniknya:

StateDeskripsiContoh Visual
LoadingMenunggu data/fetch prosesSpinner, Skeleton, Dots
SuccessData sukses diterima & tampilkanTampilan data
ErrorAda failure dari backend/jaringan/validasiBanner/Toast/Error Page/Retry
EmptyData tidak ada tetapi bukan errorIlustrasi kosong, Call to Action

Implementasi Dasar Error & Loading Handling di React

Langsung saja ke contoh kode React (hampir semua framework SPA prinsipnya sama):

import { useEffect, useState } from "react";

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // Simulasi: random sukses/error.
      Math.random() > 0.3
        ? resolve(["Apple", "Banana", "Orange"])
        : reject(new Error("Failed fetch data!"));
    }, 1000);
  });
}

export function FruitList() {
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState([]);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchData()
      .then((fruits) => {
        setData(fruits);
        setLoading(false);
      })
      .catch((err) => {
        setError(err.message);
        setLoading(false);
      });
  }, []);

  if (loading) return <div>Loading...</div>;
  if (error)   return <div style={{color:"red"}}>Oops: {error}</div>;
  if (data.length === 0) return <div>No fruits found.</div>;

  return (
    <ul>
      {data.map(fruit => <li key={fruit}>{fruit}</li>)}
    </ul>
  );
}

Keterangan:

  • Kita menggunakan tiga state: loading, data, dan error.
  • Sekali fetch beres, loading dimatikan. Kalau error, tampilkan pesan error.
  • Saat sukses tapi kosong, tunjukkan pesan data kosong.

Best Practice: Miliki Satu Sumber Kebenaran “Status”

Saya sarankan untuk meng-enkapsulasi state dalam satu objek status:

const [state, setState] = useState({
  status: "idle", // atau: 'loading', 'success', 'error', 'empty'
  data: null,
  error: null
});

Alurnya kira-kira seperti berikut:

flowchart TD
    A[Memulai Fetch] --> B{Sukses?}
    B -- Ya --> C[Cek Data Kosong?]
    C -- Tidak--> D[Status = Success]
    C -- Ya --> E[Status = Empty]
    B -- Tidak --> F[Status = Error]

Daftar “85 Gaya” Handling Error & Loading di Frontend

Agar artikel ini lebih praktikal, berikut saya rangkum ide dan best-practice terkait error dan loading state dalam bentuk tabel skenario dan tekniknya—singkat padat, 85 buah:

#Skenario/PrinsipCara Handling
1Fetch APITampilkan loading spinner
2Fetch API errorMunculkan retry button dan error message
3Submit form (POST/PUT)Tombol disabled + indikator loading
4Submit error (e.g. validation)Highlight field error
5Empty state (no data)Tampilkan ilustrasi + CTA (action)
6Skeleton loadingGunakan skeleton pada fetching list/table
7Network errorTampilkan error toast/banner
8TimeoutRetry atau fallback (cached)
9Slow connectionShow “slow network” warning/loading
10Optimistic UI (ubah state sebelum sukses)Revert bila gagal dan show error
11Error boundary (React etc)Tampilkan friendly fallback UI
12Multi-request paralelPer state loading & error
13Error 401/403Paksa logout / redirect login
14Error 404Show custom Not Found page
15Error trackingKirim error ke monitoring tool
16Polling dataPastikan loading & error state per tick
84Loading berlapis (global & lokal)Loader global di navbar/app shell, loader lokal di komponen
85Animasi loading yang accessibleGunakan role=“status”/aria-live untuk screen reader ada perubahan

(Tabel lengkap dapat diunduh di Github, isinya skenario populer error/loading di frontend).


Simulasi: Handling Error Berlapis di Dashboard

Misal, sebuah dashboard ada beberapa widget yang fetch data asinkron. Simulasikan handler error dan loading per widget:

function Widget({title, fetchFn}) {
  const [state, setState] = useState({ status: 'loading', data: null, error: null});
  useEffect(() => {
    fetchFn()
      .then((data) => setState({status: data.length ? 'success' : 'empty', data, error: null}))
      .catch((err) => setState({status: 'error', data: null, error: err.message}));
  }, [fetchFn]);
  
  if (state.status === 'loading') return <div>{title}: Loading...</div>;
  if (state.status === 'error')   return <div>{title}: <span style={{color: 'red'}}>Error: {state.error}</span></div>;
  if (state.status === 'empty')   return <div>{title}: No data</div>;
  return <div>{title}: Data Ready </div>;
}

function Dashboard() {
  const fetchA = () => fetchData();
  const fetchB = () => Promise.reject(new Error("Service Down"));
  return (
    <div>
      <h2>Dashboard</h2>
      <Widget title="Widget A" fetchFn={fetchA} />
      <Widget title="Widget B" fetchFn={fetchB} />
    </div>
  );
}

Error Boundary di React (Untuk Render Error Robust)

Untuk error saat rendering komponennya, gunakan error boundary:

class ErrorBoundary extends React.Component {
  state = { hasError: false, error: null };
  
  static getDerivedStateFromError(error) {
    return {hasError: true, error};
  }

  componentDidCatch(error, errorInfo) {
    // Kirim ke Sentry/monitoring dsb
    logErrorToService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) return <div>Oh Snap! Something went wrong.</div>;
    return this.props.children;
  }
}

Pakai wrapper di App component:

<ErrorBoundary>
  <App />
</ErrorBoundary>

Loading State yang Accessible

Pastikan loader readable oleh screen reader:

<div role="status" aria-live="polite">
  Loading fruits, please wait...
</div>

Penutup: Handling Error & Loading itu 80% UX!

Selain memperhatikan flow utama, error dan loading state adalah “sandiwara backend” yang harus kita perhalus. Dengan 85 prinsip dan teknik di atas, dijamin aplikasi Anda akan lebih pro, handal—dan lebih dicintai user!

Tips Terakhir:

  • Jangan tampilkan error teknis langsung ke user (misal: stacktrace).
  • Sediakan “retry”, dan edukasi user jika perlu.
  • Buat reusable component untuk status handler!

Bagikan pengalaman error/loading handling kamu di kolom komentar!


Sampai jumpa di artikel berikutnya. Happy Handling Error! 🚀


Referensi:

Artikel lain tentang best practice frontend: lihat di profil pribadi saya di Medium.

comments powered by Disqus