Skip to content

Category Picker Salah Modul Saat Edit: Tri-State yang Benar

Adityo Guni Waluyo

Dropdown kategori yang benar untuk create ternyata salah untuk edit. Tri-state moduleScope dan effect yang menunggu scope resolve.

Ringkasan

Gue kira dropdown ngaco karena loading lemot, ternyata fetch-nya kecepetan sebelum tau modulnya apa. Solusinya pake tri-state buat moduleScope, jadi kalo masih undefined ditahan dulu jangan fetch. Begitu modul udah jelas baru fetch kategori, hasilnya jadi akurat nggak ketuker lagi.

Saya lagi ngetes form edit untuk sebuah entitas di modul non-PARIWISATA. Pas klik dropdown kategori, yang muncul malah daftar kategori milik PARIWISATA. Bukan kosong, tapi salah total. Opsi yang tampil itu valid secara database, cuma bukan milik modul yang lagi saya edit.

Tebakan Awal yang Meleset

Awalnya saya kira ini masalah loading state biasa. Logika saya waktu itu sederhana banget. Kalo datanya belum ada, tampilkan spinner loading. Kalo udah ada, langsung render opsi kategori ke layar. Cukup pakai satu boolean isLoading buat ngecek apakah data kategori udah siap diambil dari server.

Ternyata tebakan ini meleset jauh. Masalahnya bukan di kecepatan loading atau jaringan yang lambat. Masalahnya ada di kapan data itu sebenarnya diminta. Dropdown yang langsung fetch kategori pas komponen di-mount itu benar untuk mode create, tapi salah besar untuk mode edit. Di mode edit, modul baru diketahui setelah data entitasnya selesai dimuat. Kalo kita maksa fetch di awal, kita cuma dapat data default atau data yang kebetulan nge-cache sebelumnya.

Solusi Tri-State dan Sinkronisasi Efek

Setelah ngecek kode lebih dalam, saya sadar picker ini punya tiga kondisi berbeda, bukan cuma dua kondisi hidup atau mati. Saya butuh variabel moduleScope dengan useState bertipe tri-state.

Kondisi pertama adalah string, misalnya "PARIWISATA". Ini terjadi saat modul udah diketahui langsung dari prop, yang biasanya terjadi di mode create. Kondisi kedua adalah undefined, state penunggu saat kita sedang di mode edit dan masih menunggu entitas dimuat dari server. Kondisi ketiga adalah null, yang berfungsi sebagai fallback ke seluruh scope bidang kalo emang nggak ada batasan modul yang spesifik.

Fetch data harus menunggu scope ini resolve dengan pasti. Inti perubahannya di dependency effect:

useEffect(() => {
  if (moduleScope === undefined) return; // edit: tunggu entitas dimuat
  adminApi.listAdminCategories(moduleScope ? { module: moduleScope } : {})
    .then((cats) => setCategories(cats));
}, [moduleScope]);

Pola ini emang sesuai panduan resmi React tentang sinkronisasi dengan sistem eksternal [7]. Dokumentasi juga menyebut bahwa rantai Effects itu hal yang wajar dan justru dianjurkan saat kita perlu sinkronisasi dengan jaringan [11]. Kita nggak bisa maksa data kategori muncul sebelum kita tahu entitasnya milik modul apa. Membiarkan useEffect menunggu dependency berubah adalah cara paling aman untuk menghindari race condition.

Ada juga masalah pergeseran kontrak yang perlu diperhatikan di sisi backend. Waktu saya nambahin modul baru kayak KEPEMUDAAN, perubahan ini nggak boleh cuma dilakukan di satu tempat aja. Enum di openapi.yaml harus diperbarui terlebih dahulu. Setelah itu, file v1.d.ts yang di-generate ulang harus ikut berubah secara otomatis. Terakhir, daftar MODULES di kategori-view.tsx juga wajib disesuaikan agar frontend punya referensi yang lengkap.

OpenAPI adalah kontrak yang bisa dibaca mesin [6], jadi ketiga elemen ini harus jalan bareng tanpa ada yang tertinggal. Kalo nggak, frontend bakal bingung nerjemahin tipe data yang dikirim backend dan bisa memicu error tipe yang sulit dilacak.

Saya juga sempat nemu kasus unik di wisata/baru/page.tsx. Default value di situ udah di-set keras ke "PARIWISATA". Tapi kalo ada parameter asing di URL, parameter itu diabaikan begitu aja karena default-nya terlalu kaku. Ini bikin saya makin yakin kalo state modul harus dikelola dengan eksplisit pakai tri-state, bukan cuma ngandelin default value yang gampang bikin bug di kasus edge.

Dengan pendekatan ini, dropdown kategori sekarang selalu menampilkan opsi yang relevan. Nggak ada lagi kategori yang nyasar ke modul lain cuma karena kita lupa menunggu state entitas selesai dimuat. Prosesnya jadi lebih predictable, dan debugging-nya jauh lebih gampang karena alur datanya jelas: tunggu scope, baru fetch.

Sumber

Artikel terkait