Pelajari cara merefaktor komponen React dengan Claude Code menggunakan tes karakterisasi, langkah kecil yang aman, dan pemisahan state untuk memperbaiki struktur tanpa mengubah perilaku.

Refaktor React terasa berisiko karena kebanyakan komponen bukanlah blok bangunan kecil yang bersih. Mereka adalah tumpukan hidup UI, state, efek, dan perbaikan "tambahan satu prop". Saat Anda mengubah struktur, seringkali Anda mengubah timing, identitas, atau aliran data tanpa sengaja.
Refaktor mengubah perilaku paling sering ketika secara tidak sengaja ia:
key berubah.Refaktor juga berubah menjadi rewrite ketika “pembersihan” bercampur dengan “perbaikan.” Anda mulai dengan mengekstrak komponen, lalu mengganti nama banyak hal, lalu “memperbaiki” bentuk state, lalu mengganti sebuah hook. Tak lama kemudian Anda mengubah logika sambil juga mengubah layout. Tanpa pengaman, sulit mengetahui perubahan mana yang menyebabkan bug.
Refaktor yang aman punya satu janji sederhana: pengguna mendapat perilaku yang sama, dan Anda berakhir dengan kode yang lebih jelas. Props, event, state loading, state error, dan edge case harus berperilaku sama. Jika perilaku berubah, itu harus disengaja, kecil, dan disebutkan dengan jelas.
Jika Anda merefaktor komponen React dengan Claude Code (atau asisten coding apa pun), perlakukan ia seperti pasangan kerja cepat, bukan autopilot. Minta ia menjelaskan risiko sebelum mengedit, usulkan rencana dengan langkah-langkah kecil dan aman, dan jelaskan bagaimana ia memeriksa bahwa perilaku tetap sama. Lalu validasi sendiri: jalankan aplikasi, klik jalur-jalur aneh, dan andalkan tes yang menangkap apa yang komponen lakukan hari ini, bukan yang Anda harapkan.
Pilih satu komponen yang nyata-nyata memakan waktu Anda. Bukan seluruh halaman, bukan “lapisan UI,” dan bukan “pembersihan” yang kabur. Pilih satu komponen yang susah dibaca, susah diubah, atau penuh state dan efek yang rapuh. Target yang sempit juga membuat saran asisten lebih mudah diverifikasi.
Tulis tujuan yang bisa Anda cek dalam lima menit. Tujuan yang baik berkaitan dengan struktur, bukan hasil: “pisah menjadi komponen yang lebih kecil,” “buat state lebih mudah diikuti,” atau “buat bisa dites tanpa mem-mock setengah aplikasi.” Hindari tujuan seperti “buat lebih baik” atau “tingkatkan performa” kecuali Anda punya metrik dan bottleneck yang jelas.
Tetapkan batasan sebelum membuka editor. Refaktor yang paling aman itu membosankan:
Lalu daftarkan dependensi yang bisa diam-diam memecah perilaku saat Anda memindahkan kode: panggilan API, provider context, parameter routing, feature flag, event analytics, dan state global bersama.
Contoh konkret: Anda punya OrdersTable 600 baris yang mengambil data, memfilternya, mengelola seleksi, dan menampilkan drawer dengan detail. Tujuan yang jelas bisa jadi: “ekstrak render baris dan UI drawer menjadi komponen, dan pindahkan state seleksi ke satu reducer, tanpa perubahan UI.” Tujuan itu mengatakan seperti apa “selesai” dan apa yang di luar cakupan.
Sebelum merefaktor, perlakukan komponen seperti kotak hitam. Tugas Anda adalah menangkap apa yang ia lakukan hari ini, bukan apa yang Anda inginkan. Ini menjaga refaktor agar tidak berubah jadi redesign.
Mulai dengan menuliskan perilaku saat ini dalam bahasa biasa: dengan input ini, UI menunjukkan keluaran itu. Sertakan props, parameter URL, feature flag, dan data apa pun yang berasal dari context atau store. Jika Anda memakai Claude Code, tempelkan potongan kecil yang fokus dan minta ia menyatakan ulang perilaku sebagai kalimat-kalimat tepat yang bisa Anda periksa nanti.
Cover state UI yang benar-benar dilihat orang. Sebuah komponen bisa terlihat baik di jalur bahagia sementara rusak saat memasuki loading, empty, atau error.
Juga tangkap aturan implisit yang mudah terlewat dan sering menyebabkan refaktor merusak perilaku:
Contoh: Anda punya tabel pengguna yang memuat hasil, mendukung pencarian, dan mengurut menurut “Last active.” Tuliskan apa yang terjadi ketika pencarian kosong, ketika API mengembalikan list kosong, ketika API error, dan ketika dua pengguna punya waktu “Last active” yang sama. Catat detail kecil seperti apakah pengurutan case-insensitive, dan apakah tabel mempertahankan halaman saat filter berubah.
Saat catatan Anda terasa membosankan dan spesifik, Anda siap.
Characterization tests adalah tes “ini yang dilakukan sekarang.” Mereka menggambarkan perilaku saat ini, bahkan ketika itu aneh, tidak konsisten, atau jelas bukan yang Anda inginkan dalam jangka panjang. Kedengarannya berlawanan, tapi mereka menjaga refaktor agar tidak diam-diam berubah menjadi rewrite.
Saat Anda merefaktor komponen React dengan Claude Code, tes ini adalah rel keselamatan Anda. Alat bisa membantu merombak kode, tetapi Anda yang menentukan apa yang tidak boleh berubah.
Fokus pada apa yang bergantung pada pengguna (dan kode lain):
Untuk menjaga tes stabil, assert hasil, bukan implementasi. Lebih baik “tombol Save menjadi disabled dan sebuah pesan muncul” daripada “setState dipanggil” atau “hook ini dijalankan.” Jika tes gagal karena Anda mengganti nama komponen atau mengubah urutan hook, tes itu tidak melindungi perilaku.
Perilaku async adalah tempat refaktor sering mengubah timing. Perlakukan ini secara eksplisit: tunggu UI mereda, lalu lakukan assert. Jika ada timer (debounced search, toast tertunda), gunakan fake timer dan majukan waktunya. Jika ada panggilan network, mock fetch dan assert apa yang pengguna lihat setelah sukses dan setelah gagal. Untuk alur ala Suspense, uji fallback dan tampilan yang selesai.
Contoh: tabel “Users” hanya menampilkan “No results” setelah pencarian selesai. Characterization test harus mengunci urutan itu: indikator loading dulu, lalu baris atau pesan kosong, terlepas bagaimana Anda nantinya memecah komponen.
Keberhasilan bukanlah “perubahan besar lebih cepat.” Keberhasilan adalah mendapatkan gambaran jelas tentang apa yang komponen lakukan, lalu mengubah satu hal kecil pada satu waktu sambil menjaga perilaku tetap stabil.
Mulailah dengan menempelkan komponen dan minta ringkasan tanggung jawab dalam bahasa Inggris biasa (atau bahasa yang Anda pakai). Dorong untuk spesifik: data apa yang ditampilkan, aksi pengguna apa yang ditangani, dan side effect apa yang dipicu (fetching, timer, subscription, analytics). Ini sering mengekspos pekerjaan tersembunyi yang membuat refaktor berisiko.
Selanjutnya, minta peta dependensi. Anda ingin inventaris semua input dan output: props, pembacaan context, custom hook, local state, nilai turunan, efek, dan helper tingkat modul. Peta yang berguna juga menunjukkan apa yang aman dipindah (perhitungan murni) versus apa yang “lengket” (timing, DOM, network).
Lalu minta ia mengusulkan kandidat ekstraksi, dengan satu aturan ketat: pisahkan bagian view murni dari bagian controller yang stateful. Bagian JSX yang banyak dan hanya butuh props adalah kandidat ekstraksi pertama yang baik. Bagian yang mencampur handler event, panggilan async, dan update state biasanya bukan.
Workflow yang tahan di kode nyata:
Checkpoint penting. Minta Claude Code rencana minimal di mana tiap langkah bisa di-commit dan dibalik. Checkpoint praktis bisa jadi: “Ekstrak <TableHeader> tanpa perubahan logika” sebelum menyentuh sorting state.
Contoh konkret: jika komponen merender tabel customer, mengontrol filter, dan mengambil data, ekstrak markup tabel dulu (header, row, empty state) menjadi komponen murni. Baru setelah itu pindahkan state filter atau effect fetch. Urutan ini menjaga bug tidak ikut terbawa bersama JSX.
Saat Anda memecah komponen besar, risikonya bukan memindahkan JSX. Risikonya adalah mengubah aliran data, timing, atau wiring event tanpa sengaja. Perlakukan ekstraksi sebagai latihan salin-dan-wiring dulu, dan pembersihan belakangan.
Mulailah dengan mencari batas yang sudah ada di UI, bukan di struktur file Anda. Cari bagian yang sudah bisa Anda gambarkan sebagai “sesuatu” dalam satu kalimat: header dengan aksi, filter bar, daftar hasil, footer dengan paginasi.
Langkah pertama yang aman adalah mengekstrak komponen presentasional murni: props masuk, JSX keluar. Buat mereka membosankan dengan sengaja. Tidak ada state baru, tidak ada efek, tidak ada panggilan API. Jika komponen awal punya click handler yang melakukan tiga hal, simpan handler itu di parent dan oper turun.
Batas aman yang biasanya bekerja: area header, daftar dan item row, filter (hanya input), kontrol footer (paginasi, total, aksi massal), dan dialog (open/close dan callback dioper).
Penamaan lebih penting daripada yang disangka orang. Pilih nama spesifik seperti UsersTableHeader atau InvoiceRowActions. Hindari nama umum seperti “Utils” atau “HelperComponent” karena menyamarkan tanggung jawab dan mengundang pencampuran concern.
Kenalkan container component hanya bila benar-benar perlu: sepotong UI yang harus memiliki state atau efek agar tetap koheren. Bahkan saat itu, buat sempit. Container yang baik punya satu tujuan (mis. “state filter”) dan menyerahkan sisanya lewat prop.
Komponen berantakan biasanya mencampur tiga jenis data: UI state nyata (apa yang diubah pengguna), data turunan (yang bisa dihitung), dan server state (yang datang dari network). Jika Anda memperlakukan semuanya sebagai state lokal, refaktor menjadi berisiko karena Anda bisa mengubah kapan sesuatu diperbarui.
Mulailah dengan memberi label tiap bagian data. Tanyakan: apakah pengguna mengeditnya, atau bisa saya hitung dari props, state, dan data yang di-fetch? Juga tanyakan: apakah nilai ini dimiliki di sini, atau hanya diteruskan?
Nilai turunan tidak seharusnya berada di useState. Pindahkan ke fungsi kecil, atau selector yang dimemoisasi jika mahal. Ini mengurangi update state dan membuat perilaku lebih mudah diprediksi.
Pola aman:
useState.useMemo.Efek merusak perilaku ketika melakukan terlalu banyak atau bereaksi pada dependensi yang salah. Bidik satu efek per tujuan: satu untuk sinkron ke localStorage, satu untuk fetching, satu untuk subscription. Jika sebuah effect membaca banyak nilai, biasanya ia menyembunyikan tanggung jawab ekstra.
Jika Anda memakai Claude Code, minta perubahan kecil: bagi satu effect menjadi dua, atau pindahkan satu tanggung jawab ke helper. Lalu jalankan characterization tests setelah tiap perubahan.
Waspadai prop drilling. Mengganti dengan context membantu hanya bila mengurangi wiring berulang dan memperjelas kepemilikan. Tanda bagus adalah ketika konteks terasa seperti konsep level-app (current user, theme, feature flags), bukan jalan pintas untuk satu pohon komponen.
Contoh: sebuah komponen tabel mungkin menyimpan rows dan filteredRows di state. Simpan rows di state, hitung filteredRows dari rows dan query, dan taruh kode filtering di fungsi murni agar mudah dites dan susah rusak.
Refaktor salah paling sering ketika Anda mengubah terlalu banyak sebelum menyadarinya. Solusinya sederhana: bekerja dalam checkpoint kecil, dan perlakukan setiap checkpoint seperti rilis mini. Meski Anda bekerja di satu branch, jaga perubahan agar muat di PR sehingga Anda bisa melihat apa yang rusak dan kenapa.
Setelah setiap langkah berarti (ekstraksi komponen, mengubah aliran state), berhenti dan buktikan Anda tidak mengubah perilaku. Bukti itu bisa otomatis (tes) dan manual (cek cepat di browser). Tujuannya bukan kesempurnaan. Melainkan deteksi cepat.
Loop checkpoint praktis:
Jika Anda memakai platform seperti Koder.ai, snapshot dan rollback bisa bertindak sebagai pengaman saat Anda iterasi. Anda tetap butuh commit normal, tetapi snapshot membantu saat Anda perlu membandingkan versi “dikenal baik” dengan versi saat ini, atau ketika eksperimen berantakan.
Simpan ledger perilaku sederhana saat berjalan. Hanya catatan singkat apa yang Anda verifikasi, agar tidak memeriksa hal yang sama berulang kali.
Contoh:
Saat sesuatu rusak, ledger memberi tahu apa yang harus diperiksa ulang, dan checkpoint membuatnya murah untuk mundur.
Kebanyakan refaktor gagal dalam cara kecil dan membosankan. UI masih bekerja, tetapi aturan spasi hilang, handler klik terpanggil dua kali, atau daftar kehilangan fokus saat mengetik. Asisten bisa memperparah karena kode terlihat lebih bersih sementara perilaku bergeser.
Salah satu penyebab umum adalah perubahan struktur. Anda mengekstrak komponen dan membungkus dengan \u003cdiv\u003e tambahan, atau mengganti \u003cbutton\u003e dengan \u003cdiv\u003e yang clickable. Selector CSS, layout, navigasi keyboard, dan query tes bisa berubah tanpa ada yang menyadari.
Perangkap yang sering memecah perilaku:
{} atau () => {}) dapat memicu re-render tambahan dan mereset state anak. Perhatikan prop yang dulu stabil.useEffect, useMemo, atau useCallback dapat memperkenalkan nilai usang atau loop jika dependensi berubah. Jika efek dulu berjalan “saat klik”, jangan ubah jadi sesuatu yang berjalan “kapan pun apa pun berubah.”Contoh konkret: memecah komponen tabel dan mengganti key baris dari ID ke indeks array mungkin terlihat baik, tetapi bisa memecah state seleksi saat baris diurut ulang. Perlakukan “bersih” sebagai bonus. Perlakukan “perilaku sama” sebagai persyaratan.
Sebelum merge, Anda ingin bukti bahwa refaktor mempertahankan perilaku. Sinyal termudah itu membosankan: semuanya masih bekerja tanpa Anda harus “memperbaiki” tes.
Lakukan pemeriksaan cepat ini setelah perubahan kecil terakhir:
onChange masih dipanggil saat input pengguna, bukan saat mount).Cek cepat: buka komponen dan jalankan satu jalur aneh, seperti memicu error, retry, lalu menghapus filter. Refaktor sering merusak transisi meski jalur utama masih bekerja.
Jika ada item gagal, revert perubahan terakhir dan ulangi dalam langkah yang lebih kecil. Itu biasanya lebih cepat daripada debugging diff besar.
Bayangkan ProductTable yang melakukan semuanya: fetch data, mengelola filter, kontrol paginasi, membuka dialog konfirmasi untuk hapus, dan menangani aksi baris seperti edit, duplicate, dan archive. Ia mulai kecil, lalu tumbuh menjadi file 900 baris.
Gejalanya khas: state tersebar di banyak useState, beberapa useEffect berjalan dalam urutan tertentu, dan satu perubahan “sepele” merusak paginasi hanya saat filter aktif. Orang berhenti menyentuhnya karena terasa tak terduga.
Sebelum mengubah struktur, kunci perilaku dengan beberapa characterization tests React. Fokus pada apa yang pengguna lakukan, bukan state internal:
Sekarang Anda bisa merefaktor dalam commit kecil. Rencana ekstraksi bersih bisa terlihat seperti ini: FilterBar merender kontrol dan memancarkan perubahan filter; TableView merender row dan paginasi; RowActions memegang menu aksi dan UI dialog konfirmasi; dan hook useProductTable memegang logika kusut (query params, nilai turunan, dan side effect).
Urutan penting. Ekstrak UI bodoh dulu (TableView, FilterBar) dengan meneruskan prop tanpa perubahan. Simpan bagian berisiko untuk terakhir: memindahkan state dan efek ke useProductTable. Saat melakukannya, pertahankan nama prop lama dan bentuk event sehingga tes tetap lulus. Jika tes gagal, Anda menemukan perubahan perilaku, bukan masalah style.
Jika Anda ingin merefaktor komponen React dengan Claude Code terasa aman setiap kali, ubah apa yang baru saja Anda lakukan menjadi template kecil yang bisa dipakai ulang. Tujuannya bukan menambah proses. Tujuannya mengurangi kejutan.
Tulis playbook singkat yang bisa Anda ikuti pada komponen mana pun, bahkan saat lelah atau terburu-buru:
Simpan ini sebagai snippet di catatan atau repo sehingga refaktor berikutnya dimulai dengan pengaman yang sama.
Setelah komponen stabil dan lebih mudah dibaca, pilih pass berikutnya berdasarkan dampak pengguna. Urutan umum: aksesibilitas dulu (label, fokus, keyboard), lalu performa (memoization, render mahal), lalu pembersihan (types, penamaan, kode mati). Jangan gabungkan ketiganya dalam satu PR.
Jika Anda memakai workflow vibe-coding seperti Koder.ai (koder.ai), mode perencanaan dapat membantu merancang langkah sebelum menyentuh kode, dan snapshot serta rollback bisa jadi checkpoint saat Anda iterasi. Saat selesai, mengekspor source mempermudah meninjau diff akhir dan menjaga riwayat tetap bersih.
Berhenti merefaktor ketika tes menutupi perilaku yang Anda takutkan untuk rusak, perubahan berikutnya akan menjadi fitur baru, atau Anda mulai merasa ingin “menyempurnakan” segala hal. Jika memecah form besar menghilangkan state kusut dan tes menutupi validasi serta submit, kirimkan. Simpan ide tersisa sebagai backlog singkat untuk nanti.
Refaktor React sering mengubah identitas dan waktu tanpa Anda sadari. Beberapa kerusakan perilaku yang umum meliputi:
key berubah.Anggap perubahan struktur sebagai potensi perubahan perilaku sampai tes membuktikan sebaliknya.
Gunakan tujuan yang ketat dan bisa dicek, berfokus pada struktur, bukan “perbaikan”. Contoh tujuan yang baik:
Hindari tujuan seperti “buat lebih baik” kecuali Anda punya metrik spesifik dan bottleneck yang jelas.
Perlakukan komponen sebagai kotak hitam dan tuliskan apa yang bisa diamati pengguna saat ini:
Jika catatan Anda terasa membosankan dan spesifik, berarti mereka berguna.
Tambahkan characterization tests yang menggambarkan apa yang komponen lakukan hari ini, meskipun itu aneh.
Target praktis:
Asser hasil di UI, bukan panggilan hook internal.
Gunakan seperti pasangan kerja yang hati-hati:
Jangan terima diff besar bergaya rewrite; dorong perubahan inkremental yang bisa Anda verifikasi.
Mulai dengan mengekstrak bagian presentasional murni:
Salin-dan-wiring dulu; bersihkan kemudian. Setelah UI aman terpisah, baru urus state/efek dalam langkah-langkah kecil.
Gunakan kunci yang stabil terkait identitas nyata (seperti ID), jangan pakai indeks array.
Kunci indeks sering “berfungsi” sampai Anda melakukan sort, filter, insert, atau remove—lalu React menggunakan ulang instance yang salah dan muncul bug seperti:
Jika refaktor Anda mengubah key, anggap itu berisiko tinggi dan uji kasus reorder.
Jangan simpan nilai turunan di useState jika bisa dihitung dari input lain.
Pendekatan aman:
filteredRows) dari + Gunakan checkpoint supaya setiap langkah mudah dikembalikan:
Jika Anda memakai Koder.ai, snapshot dan rollback melengkapi commit biasa saat eksperimen melenceng.
Berhenti ketika perilaku terkunci dan kode menjadi jelas lebih mudah diubah. Sinyal berhenti yang baik:
Deploy refactor, lalu simpan item seperti aksesibilitas, performa, dan pembersihan sebagai pekerjaan terpisah.
rowsqueryuseMemo hanya bila komputasi beratIni mengurangi keanehan update dan memudahkan penalaran komponen.