Model mental React membuat React terasa sederhana: pelajari gagasan utama tentang komponen, rendering, state, dan effect, lalu terapkan untuk membangun UI cepat lewat chat.

React bisa terasa membuat frustrasi pada awalnya karena Anda melihat UI berubah, tapi tidak selalu bisa menjelaskan kenapa itu berubah. Anda klik tombol, sesuatu terupdate, lalu bagian lain halaman mengejutkan Anda. Biasanya itu bukan “React aneh.” Itu lebih ke “gambaran saya tentang apa yang React lakukan masih buram.”
Model mental adalah cerita sederhana yang Anda katakan pada diri sendiri tentang bagaimana sesuatu bekerja. Jika ceritanya salah, Anda akan membuat keputusan yakin yang berujung pada hasil yang membingungkan. Pikirkan termostat: model buruk adalah “saya set 22°C, jadi ruangan langsung jadi 22°C.” Model yang lebih baik adalah “saya set target, dan pemanas menyala/mati seiring waktu untuk mencapainya.” Dengan cerita yang lebih baik, perilaku berhenti terasa acak.
React bekerja sama. Setelah Anda mengadopsi beberapa ide yang jelas, React menjadi dapat diprediksi: Anda bisa melihat data saat ini dan menebak dengan andal apa yang akan tampil di layar.
Dan Abramov membantu mempopulerkan pola pikir “buat jadi dapat diprediksi” ini. Tujuannya bukan menghafal aturan. Tujuannya menyimpan beberapa kebenaran kecil di kepala sehingga Anda bisa debugging dengan bernalar, bukan coba-coba.
Pegang ide-ide ini:
Pegang itu dan React berhenti terasa seperti sulap. Ia mulai terasa sebagai sistem yang bisa Anda percaya.
React jadi lebih mudah ketika Anda berhenti berpikir dalam “layar” dan mulai berpikir dalam potongan kecil. Komponen adalah unit UI yang dapat digunakan ulang. Ia menerima input dan mengembalikan deskripsi seperti apa UI harus terlihat untuk input itu.
Membantu jika Anda menganggap komponen sebagai deskripsi murni: “diberi data ini, tampilkan ini.” Deskripsi itu bisa dipakai di banyak tempat karena tidak tergantung di mana ia tinggal.
Props adalah input. Mereka datang dari komponen induk. Props bukan “milik” komponen, dan bukan sesuatu yang seharusnya diubah diam-diam oleh komponen. Jika sebuah tombol menerima label="Save", tugas tombol adalah merender label itu, bukan memutuskan harus berbeda.
State adalah data yang dimiliki. Itu yang diingat komponen seiring waktu. State berubah saat pengguna berinteraksi, saat request selesai, atau saat Anda memutuskan sesuatu harus berbeda. Berbeda dengan props, state milik komponen itu (atau komponen mana pun yang Anda pilih untuk memilikinya).
Versi sederhana dari ide kunci: UI adalah fungsi dari state. Jika state bilang “loading,” tampilkan spinner. Jika state bilang “error,” tampilkan pesan. Jika state bilang “items = 3,” render tiga baris. Tugas Anda menjaga UI membaca dari state, bukan melayang ke variabel tersembunyi.
Cara cepat memisahkan konsep:
SearchBox, ProfileCard, CheckoutForm)name, price, disabled)isOpen, query, selectedId)Contoh: sebuah modal. Induk bisa mengoper title dan onClose sebagai props. Modal mungkin memiliki isAnimating sebagai state.
Bahkan jika Anda menghasilkan UI lewat chat (misalnya di Koder.ai), pemisahan ini tetap cara tercepat untuk tetap waras: putuskan dulu mana yang props vs state, lalu biarkan UI mengikuti.
Cara berguna memegang React di kepala (sangat sesuai semangat Dan Abramov) adalah: rendering adalah sebuah perhitungan, bukan pekerjaan mengecat. React menjalankan fungsi komponen Anda untuk menentukan seperti apa UI harus terlihat untuk props dan state saat ini. Outputnya adalah deskripsi UI, bukan piksel.
Re-render hanya berarti React mengulangi perhitungan itu. Itu tidak berarti “seluruh halaman digambar ulang.” React membandingkan hasil baru dengan yang sebelumnya dan menerapkan set perubahan terkecil ke DOM nyata. Banyak komponen bisa re-render sementara hanya beberapa node DOM yang benar-benar diperbarui.
Sebagian besar re-render terjadi karena beberapa alasan sederhana: state komponen berubah, props-nya berubah, atau induk re-render dan React meminta anak untuk render lagi. Yang terakhir sering mengejutkan orang, tapi biasanya tidak masalah. Jika Anda memperlakukan render sebagai “murah dan membosankan,” aplikasi Anda tetap lebih mudah ditangani.
Aturan praktis yang menjaga ini bersih: buat render murni. Dengan input yang sama (props + state), komponen Anda harus mengembalikan deskripsi UI yang sama. Singkirkan kejutan dari render.
Contoh konkret: jika Anda menghasilkan ID dengan Math.random() di dalam render, re-render mengubahnya dan tiba-tiba sebuah checkbox kehilangan fokus atau item list remount. Buat ID sekali (state, memo, atau di luar komponen) dan render menjadi stabil.
Jika Anda ingat satu kalimat: re-render berarti “hitung ulang seperti apa UI seharusnya,” bukan “bangun ulang semuanya.”
Model berguna lain: update state adalah permintaan, bukan penugasan instan. Ketika Anda memanggil setter seperti setCount(count + 1), Anda meminta React menjadwalkan render dengan nilai baru. Jika Anda membaca state segera setelahnya, Anda mungkin masih melihat nilai lama karena React belum merender.
Itulah kenapa update yang “kecil dan dapat diprediksi” penting. Lebih baik menggambarkan perubahan daripada mengandalkan apa yang Anda kira nilai saat ini. Saat nilai berikutnya tergantung pada yang sebelumnya, gunakan bentuk updater: setCount(c => c + 1). Ini cocok dengan cara kerja React: beberapa update dapat antre, lalu diterapkan sesuai urutan.
Immutability adalah separuh gambar lainnya. Jangan ubah objek dan array di tempat. Buat yang baru dengan perubahan itu. React kemudian bisa melihat “nilai ini baru,” dan otak Anda bisa menelusuri apa yang berubah.
Contoh: toggling sebuah todo. Pendekatan aman adalah membuat array baru dan objek todo baru untuk item yang Anda ubah. Pendekatan berisiko adalah membalik todo.done = !todo.done di dalam array yang sudah ada.
Juga jaga state seminimal mungkin. Perangkap umum adalah menyimpan nilai yang bisa dihitung. Jika Anda sudah punya items dan filter, jangan simpan filteredItems di state. Hitung saat render. Lebih sedikit variabel state berarti lebih sedikit cara nilai bisa keluar dari sinkron.
Tes sederhana untuk apa yang masuk state:
Jika Anda membangun UI lewat chat (termasuk di Koder.ai), mintalah perubahan sebagai patch kecil: “Tambahkan satu boolean” atau “Perbarui daftar ini secara immutable.” Perubahan kecil dan eksplisit menjaga generator dan kode React Anda selaras.
Rendering menggambarkan UI. Effect menyinkronkan dengan dunia luar. “Luar” berarti hal-hal yang React tidak kendalikan: panggilan jaringan, timer, API browser, dan kadang pekerjaan DOM imperatif.
Jika sesuatu bisa dihitung dari props dan state, biasanya tidak seharusnya berada di effect. Menaruhnya di effect menambah langkah kedua (render, jalankan effect, set state, render lagi). Lompatan ekstra itu tempat munculnya flicker, loop, dan bug “kenapa ini kadaluarsa?”.
Kebingungan umum: Anda punya firstName dan lastName, lalu menyimpan fullName di state menggunakan effect. Tapi fullName bukan side effect. Itu data turunan. Hitung saat render dan ia akan selalu cocok.
Sebagai kebiasaan: turunkan nilai UI saat render (atau pakai useMemo bila memang mahal), dan gunakan effect untuk “melakukan sesuatu”, bukan “menentukan sesuatu”.
Perlakukan dependency array sebagai: “Ketika nilai-nilai ini berubah, sinkron ulang dengan dunia luar.” Ini bukan trik performa dan bukan tempat untuk menonaktifkan peringatan.
Contoh: jika Anda fetch detail user ketika userId berubah, userId masuk dependency array karena itu harus memicu sinkronisasi. Jika effect juga menggunakan token, sertakan juga, atau Anda mungkin fetch dengan token lama.
Cek insting yang baik: jika menghapus suatu effect hanya akan membuat UI salah, mungkin itu bukan effect sejati. Jika menghapusnya akan menghentikan timer, membatalkan subscription, atau melewatkan fetch, kemungkinan itu memang effect.
Salah satu model mental paling berguna sederhana: data turun ke pohon, dan aksi pengguna naik.
Induk meneruskan nilai ke anak. Anak tidak seharusnya diam-diam “menguasai” nilai yang sama di dua tempat. Mereka meminta perubahan dengan memanggil fungsi, dan induk memutuskan nilai baru.
Saat dua bagian UI perlu setuju, pilih satu tempat menyimpan nilai, lalu teruskan ke bawah. Ini adalah “lifting state.” Mungkin terasa seperti pipa ekstra, tapi mencegah masalah yang lebih buruk: dua state yang menyimpang dan memaksa Anda menambah hack untuk menyinkronkannya.
Contoh: sebuah search box dan daftar hasil. Jika input menyimpan query sendiri dan daftar juga menyimpan query sendiri, Anda akhirnya melihat “input menampilkan X tapi daftar memakai Y.” Solusinya simpan query di induk, teruskan ke keduanya, dan teruskan onChangeQuery(newValue) ke input.
Lifting state tidak selalu jawaban. Jika sebuah nilai hanya penting di dalam satu komponen, simpanlah di sana. Menjaga state dekat dengan tempat digunakan biasanya membuat kode lebih mudah dibaca.
Batas praktis:
Jika ragu harus mengangkat state, cari sinyal seperti: dua komponen menunjukkan nilai yang sama dengan cara berbeda; sebuah aksi di satu tempat harus memperbarui sesuatu jauh; Anda terus menyalin props ke state “untuk berjaga-jaga”; atau Anda menambah effect hanya untuk menjaga dua nilai sinkron.
Model ini juga membantu saat membangun lewat alat chat seperti Koder.ai: minta satu pemilik untuk tiap bagian state yang dibagi, lalu hasilkan handler yang mengalir ke atas.
Pilih fitur yang cukup kecil untuk dipegang dalam kepala. Contoh yang bagus adalah daftar yang bisa dicari di mana Anda bisa klik item untuk melihat detail di modal.
Mulai dengan mengsketsa bagian UI dan event yang bisa terjadi. Jangan pikirkan kode dulu. Pikirkan apa yang bisa dilakukan pengguna dan apa yang mereka lihat: ada input pencarian, daftar, highlight baris terpilih, dan modal. Eventnya: mengetik pencarian, klik item, buka modal, tutup modal.
Sekarang “gambar state.” Tulis beberapa nilai yang harus disimpan, dan putuskan siapa pemiliknya. Aturan sederhana bekerja baik: parent terdekat yang umum untuk semua tempat yang perlu sebuah nilai harus memilikinya.
Untuk fitur ini, state yang disimpan bisa kecil: query (string), selectedId (id atau null), dan isModalOpen (boolean). Daftar membaca query dan merender item. Modal membaca selectedId untuk menampilkan detail. Jika daftar dan modal sama-sama butuh selectedId, simpan di parent, bukan di keduanya.
Selanjutnya, pisahkan data turunan dari data yang disimpan. Daftar terfilter adalah turunan: filteredItems = items.filter(...). Jangan simpan itu di state karena selalu bisa dihitung ulang dari items dan query. Menyimpan data turunan adalah cara nilai menjadi tidak sinkron.
Baru kemudian tanya: apakah kita butuh effect? Jika items sudah di memori, tidak. Jika mengetik query harus fetch hasil, ya. Jika menutup modal harus menyimpan sesuatu, ya. Effect untuk sinkronisasi (fetch, save, subscribe), bukan untuk wiring UI dasar.
Terakhir, uji alur dengan beberapa kasus tepi:
selectedId masih valid?Jika Anda bisa menjawab itu di atas kertas, kode React biasanya langsung mudah.
Sebagian besar kebingungan React bukan tentang sintaks. Terjadi ketika kode Anda berhenti cocok dengan cerita sederhana di kepala Anda.
Menyimpan state turunan. Anda menyimpan fullName di state padahal itu hanya firstName + lastName. Bekerja sampai satu field berubah dan yang lain tidak, lalu UI menunjukkan nilai kadaluarsa.
Loop effect. Sebuah effect fetch data, set state, dan daftar dependency membuatnya berjalan lagi. Gejalanya permintaan berulang, UI goyah, atau state yang tak pernah stabil.
Closure usang. Handler klik membaca nilai lama (mis. counter atau filter yang kadaluarsa). Gejalanya “saya klik, tapi ia memakai nilai kemarin.”
State global dimana-mana. Memasukkan setiap detail UI ke store global membuat sulit mengetahui siapa yang memiliki apa. Gejalanya Anda ubah satu hal dan tiga layar merespons dengan cara mengejutkan.
Memutasi objek bersarang. Anda mengubah objek atau array di tempat dan heran kenapa UI tidak update. Gejalanya “datanya berubah, tapi tidak ada yang re-render.”
Contoh konkret: panel “search dan sort” untuk sebuah daftar. Jika Anda menyimpan filteredItems di state, ia bisa menyimpang dari items saat data baru datang. Sebaliknya, simpan input (search text, sort choice) dan hitung daftar terfilter saat render.
Dengan effect, gunakan untuk sinkronisasi dengan dunia luar (fetching, subscription, timer). Jika sebuah effect melakukan kerja UI dasar, seringkali itu lebih cocok di render atau handler event.
Saat menghasilkan atau mengedit kode lewat chat, kesalahan ini muncul lebih cepat karena perubahan bisa datang dalam potongan besar. Kebiasaan baik: ajukan permintaan dalam istilah kepemilikan: “Apa sumber kebenaran untuk nilai ini?” dan “Bisakah kita menghitung ini daripada menyimpannya?”
Ketika UI Anda mulai terasa tak terduga, biasanya bukan karena “React kebanyakan.” Biasanya terlalu banyak state, di tempat yang salah, melakukan pekerjaan yang tidak seharusnya.
Sebelum menambah useState lagi, jeda dan tanyakan:
Contoh kecil: search box, dropdown filter, list. Jika Anda menyimpan query dan filteredItems di state, Anda sekarang punya dua sumber kebenaran. Sebagai gantinya, simpan query dan filter sebagai state, lalu turunkan filteredItems saat render dari daftar penuh.
Ini penting saat Anda membangun cepat lewat alat chat juga. Kecepatan bagus, tapi terus tanyakan: “Apakah kita menambah state, atau menambah nilai turunan karena tidak sengaja?” Jika turunan, hapus state itu dan hitung saja.
Tim kecil sedang membangun UI admin: tabel pesanan, beberapa filter, dan dialog untuk mengedit pesanan. Permintaan pertama samar: “Tambah filter dan popup edit.” Kedengarannya sederhana, tapi sering berubah jadi state acak tersebar.
Jadikan konkret dengan menerjemahkan permintaan menjadi state dan event. Daripada “filters,” beri nama state: query, status, dateRange. Daripada “edit popup,” beri nama event: “user klik Edit pada baris.” Lalu putuskan siapa pemilik tiap state (halaman, tabel, atau dialog) dan apa yang bisa diturunkan (seperti daftar yang terlihat).
Contoh prompt yang menjaga model tetap utuh (juga bekerja baik di pembuat berbasis chat seperti Koder.ai):
OrdersPage yang memiliki filters dan selectedOrderId. OrdersTable dikendalikan oleh filters dan memanggil onEdit(orderId). ”visibleOrders dari orders dan filters. Jangan simpan visibleOrders di state.”EditOrderDialog yang menerima order dan open. Saat disimpan, panggil onSave(updatedOrder) dan tutup.”filters ke URL, bukan untuk menghitung baris terfilter.”Setelah UI dihasilkan atau diperbarui, tinjau perubahan dengan cek cepat: setiap nilai state punya satu pemilik, nilai turunan tidak disimpan, effect hanya untuk sinkron dengan dunia luar (URL, jaringan, storage), dan event mengalir turun sebagai props dan naik sebagai callback.
Saat state dapat diprediksi, iterasi terasa aman. Anda bisa mengubah tata letak tabel, menambah filter, atau mengubah field dialog tanpa menebak state tersembunyi mana yang akan rusak selanjutnya.
Kecepatan hanya berguna jika aplikasi tetap mudah dipahami. Perlindungan paling sederhana adalah memperlakukan model mental ini seperti daftar periksa yang Anda terapkan sebelum menulis (atau menghasilkan) UI.
Mulai setiap fitur dengan cara yang sama: tulis state yang Anda butuhkan, event yang bisa mengubahnya, dan siapa pemiliknya. Jika Anda tidak bisa mengatakan, “Komponen ini memiliki state ini, dan event ini mengupdatenya,” Anda kemungkinan akan berakhir dengan state tersebar dan re-render yang mengejutkan.
Jika Anda membangun lewat chat, mulai dengan mode perencanaan. Jelaskan komponen, bentuk state, dan transisi dalam bahasa biasa sebelum meminta kode. Contoh: “Panel filter memperbarui state query; daftar hasil menurun dari query; memilih item set selectedId; menutup mengosongkannya.” Setelah itu jelas, menghasilkan UI menjadi langkah mekanis.
Jika Anda menggunakan Koder.ai (Koder.ai) untuk menghasilkan kode React, ada baiknya melakukan pengecekan singkat sebelum melanjutkan: satu pemilik jelas untuk tiap nilai state, UI diturunkan dari state, effect hanya untuk sinkron, dan tidak ada duplikasi sumber kebenaran.
Lalu iterasi dalam langkah kecil. Jika Anda ingin mengubah struktur state (mis. dari beberapa boolean ke satu field status), ambil snapshot dulu, bereksperimen, dan rollback jika model mental memburuk. Dan saat Anda perlu review lebih dalam atau handoff, mengekspor kode sumber memudahkan menjawab pertanyaan nyata: apakah bentuk state masih menceritakan kisah UI?
Model awal yang bagus: UI = f(state, props). Komponen Anda tidak “mengedit DOM”; mereka menggambarkan apa yang harus terlihat di layar untuk data saat ini. Jika layar salah, periksa state/props yang menghasilkannya, bukan DOM.
Props adalah input dari parent; komponen Anda harus memperlakukan mereka sebagai hanya-baca. State adalah memori yang dimiliki sebuah komponen (atau komponen yang Anda pilih sebagai pemilik). Jika sebuah nilai harus dibagikan, angkat ke atas dan teruskan sebagai props.
Re-render berarti React menjalankan ulang fungsi komponen Anda untuk menghitung deskripsi UI berikutnya. Itu tidak otomatis berarti seluruh halaman dicat ulang. React kemudian memperbarui DOM nyata dengan perubahan sekecil yang diperlukan.
Karena update state dijadwalkan, bukan penugasan instan. Jika nilai berikutnya bergantung pada nilai sebelumnya, gunakan bentuk updater agar tidak bergantung pada nilai yang mungkin usang:
setCount(c => c + 1)Ini tetap benar meskipun beberapa update antre.
Hindari menyimpan apa pun yang bisa Anda hitung dari input yang ada. Simpan input, dan turunkan sisanya saat render.
Contoh:
items, filtervisibleItems = items.filter(...)Ini mencegah nilai menjadi tidak sinkron.
Gunakan effect untuk menyinkronkan dengan hal-hal yang React tidak kendalikan: fetch, subscription, timer, API browser, atau kerja DOM imperatif.
Jangan gunakan effect hanya untuk menghitung nilai UI dari state—hitung itu saat render (atau dengan useMemo jika mahal).
Perlakukan dependency array sebagai daftar pemicu: “ketika nilai-nilai ini berubah, sinkron ulang.” Sertakan setiap nilai reaktif yang dibaca effect. Jika Anda meninggalkan sesuatu, Anda berisiko menggunakan data usang (mis. userId atau token lama). Jika menambahkan hal yang salah, Anda bisa membuat loop—seringkali tanda bahwa pekerjaan itu lebih cocok di event atau render.
Jika dua bagian UI harus selalu setuju, letakkan state di parent terdekat yang sama, teruskan nilainya ke bawah, dan teruskan callback ke atas.
Tes cepat: jika Anda menduplikasi nilai di dua komponen dan menulis effect untuk “menjaganya sinkron”, kemungkinan state itu perlu satu pemilik.
Ini biasanya terjadi ketika handler ‘menangkap’ nilai lama dari render sebelumnya. Perbaikan umum:
setX(prev => ...)Jika klik menggunakan “nilai kemarin”, curigai closure usang.
Mulai dengan rencana kecil: komponen, pemilik state, dan event. Lalu hasilkan kode sebagai patch kecil (tambah satu field state, tambah satu handler, turunkan satu nilai) daripada rewrite besar.
Jika Anda menggunakan builder chat seperti Koder.ai, minta:
Itu menjaga kode yang dihasilkan selaras dengan model mental React.