React zihinsel modelleri React'i basit hissettirebilir: bileşenler, render, state ve effect'lerin arkasındaki ana fikirleri öğrenin ve ardından sohbetle hızlı UI oluşturmak için uygulayın.

React ilk başta sinir bozucu gelebilir çünkü UI'nin değiştiğini görürsünüz ama neden değiştiğini her zaman açıklayamazsınız. Bir düğmeye tıklarsınız, bir şey güncellenir ve sonra sayfanın farklı bir kısmı sizi şaşırtır. Bu genellikle “React garip” demek değildir. Asıl sorun “React'in ne yaptığına dair kafamdaki resim bulanık.”
Zihinsel model, bir şeyin nasıl çalıştığıyla ilgili kendinize anlattığınız basit hikâyedir. Eğer hikâye yanlışsa, kafa karıştıran sonuçlara yol açan emin kararlar verirsiniz. Termostatı düşünün: kötü model “22°C ayarlıyorum, oda anında 22°C olur.” Daha iyi model ise “Bir hedef ayarlıyorum ve ısıtıcı zaman içinde açılıp kapanarak hedefe ulaşmaya çalışır.” Daha iyi hikâye ile davranış rastgele hissetmeyi bırakır.
React de aynı şekilde çalışır. Birkaç net fikri benimsediğinizde React öngörülebilir olur: mevcut verilere bakıp ekranda ne olacağını güvenilir şekilde tahmin edebilirsiniz.
Dan Abramov bu “tahmin edilebilir yap” zihniyetini popülerleştirmede yardımcı oldu. Amaç kuralları ezberlemek değil. Kafanızda küçük bir doğrunun setini tutup hata ayıklamayı deneme-yanılma ile değil mantıkla yapabilmektir.
Aklınızda tutun:
Bunları tutarsanız React sihir gibi gelmeyi bırakır. Güvenebileceğiniz bir sistem gibi hissettirir.
React, “ekranlar” yerine küçük parçalarda düşünmeyi öğrendiğinizde kolaylaşır. Bir bileşen yeniden kullanılabilir bir UI birimidir. Girdiler alır ve bu girdiler için UI'nin nasıl görünmesi gerektiğinin bir tanımını döndürür.
Bir bileşeni saf bir tanım olarak görmek yardımcı olur: “bu veri verildiğinde, bunu göster.” Bu tanım bulunduğu yere bağlı olmadığı için birçok yerde kullanılabilir.
Props girdilerdir. Bir üst bileşenden gelirler. Props bileşenin “sahibi” değildir ve bileşenin bunları sessizce değiştirmesi doğru değildir. Bir buton label="Save" alıyorsa, butonun işi o etiketi render etmek, farklı olmasına karar vermek değildir.
State sahip olunan veridir. Bir bileşenin zaman içinde hatırladığı şeydir. State, kullanıcı etkileşince, bir istek bitince veya bir şeyin farklı olması gerektiğine karar verince değişir. Props'tan farklı olarak state o bileşene (veya sahip olarak seçtiğiniz bileşene) aittir.
Temel fikir sade haliyle: UI durumun bir fonksiyonudur. State “loading” diyorsa bir spinner gösterin. State “error” diyorsa bir mesaj gösterin. State “items = 3” diyorsa üç satır render edin. İşiniz UI'nın state'ten okumasını sağlamak, gizli değişkenlere kaymasını önlemektir.
Kavramları ayırmanın hızlı yolu:
SearchBox, ProfileCard, CheckoutForm)name, price, disabled)isOpen, query, selectedId)Örnek: bir modal. Üst bileşen title ve onClose gibi props geçebilir. Modal isAnimating gibi bir state'e sahip olabilir.
Hatta sohbet aracılığıyla UI üretiyorsanız (örneğin Koder.ai üzerinde), bu ayrım en hızlı şekilde aklınızı başında tutar: önce neyin props, neyin state olacağını karar verin, sonra UI'ya bırakın.
React'i kafanızda tutmanın faydalı bir yolu (Dan Abramov ruhuna uygun olarak): render bir hesaplamadır, bir boyama işi değil. React bileşen fonksiyonlarınızı çalıştırır ve mevcut props ile state için UI'nin nasıl görünmesi gerektiğini hesaplar. Çıktı piksel değil, bir UI tanımıdır.
Bir yeniden render demek React'in o hesaplamayı tekrar yapması demektir. Bu “tüm sayfa yeniden çiziliyor” demek değildir. React yeni sonucu öncekiyle karşılaştırır ve gerçek DOM'a en küçük değişiklik setini uygular. Birçok bileşen yeniden render olabilirken sadece birkaç DOM düğümü değişebilir.
Çoğu yeniden render birkaç basit sebepten olur: bir bileşenin state'i değişti, props'ları değişti veya bir üst bileşen yeniden render oldu ve React çocuktan tekrar render etmesini istedi. Bu sonuncusu insanları şaşırtır ama genelde sorun değildir. Render'ı “ucuz ve sıkıcı” olarak görürseniz uygulamanız daha kolay anlaşılır kalır.
Bu işi temiz tutacak kural: render'ı saf yapın. Aynı girdiler (props + state) verildiğinde bileşen aynı UI tanımını döndürmeli. Render içinde sürprizlere yer vermeyin.
Somut örnek: render içinde Math.random() ile bir ID üretiyorsanız, yeniden render ID'yi değiştirir ve aniden bir checkbox odağını kaybedebilir veya bir liste öğesi yeniden mount olur. ID'yi bir kez oluşturun (state, memo veya bileşen dışında) ve render stabil olur.
Hatırlamanız gereken bir cümle: bir yeniden render “UI'nin ne olması gerektiğini yeniden hesapla” demektir, “her şeyi yeniden kur” değil.
Başka faydalı bir model: state güncellemeleri isteklerdir, anlık atamalar değil. setCount(count + 1) gibi bir setter çağırdığınızda, React'e yeni bir değerle bir render planlamasını söylersiniz. Hemen sonra state'i okursanız eski değeri görebilirsiniz çünkü React henüz render etmemiştir.
Bu yüzden “küçük ve öngörülebilir” güncellemeler önemlidir. Mevcut değeri tahmin ederek almak yerine değişikliği tarif etmeyi tercih edin. Sonraki değer önceki değere bağlıysa updater formunu kullanın: setCount(c => c + 1). Bu, React'in çalışmasıyla uyuşur: birden fazla güncelleme sıraya alınabilir ve sonra sırayla uygulanır.
İmmütabilite (değişmezlik) resminin diğer yarısıdır. Nesneleri ve dizileri yerinde değiştirmeyin. Değişiklikle yeni bir tane oluşturun. React böylece “bu değer yeni” diyebilir ve beyniniz neyin değiştiğini izleyebilir.
Örnek: bir todo öğesini tersine çevirme. Güvenli yaklaşım yeni bir dizi ve değiştirdiğiniz öğe için yeni bir todo nesnesi oluşturmaktır. Riskli yaklaşım var olan dizinin içinde todo.done = !todo.done yapmaktır.
Ayrıca state'i minimal tutun. Yaygın bir tuzak, hesaplayabileceğiniz değerleri saklamaktır. Eğer zaten items ve filter varsa filteredItems'ı state'te saklamayın. Render sırasında hesaplayın. Daha az state değişkeni, değerlerin senkron dışına çıkmasının daha az yolu demektir.
State'e neyin ait olduğunun basit testi:
Eğer sohbetle UI inşa ediyorsanız (Koder.ai dahil), değişiklikleri küçük yamalar olarak isteyin: “Bir boolean bayrak ekle” veya “Bu listeyi immutably güncelle”. Küçük, açık değişiklikler üreticiyi ve React kodunuzu uyumlu tutar.
Rendering UI'yi tanımlar. Effect'ler dış dünya ile senkronize eder. “Dış dünya” dediğimiz React'in kontrol etmediği şeyler: ağ istekleri, zamanlayıcılar, tarayıcı API'leri ve bazen imperatif DOM işleri.
Bir şey props ve state'ten hesaplanabiliyorsa, genelde effect içinde olmamalıdır. Effect'e koymak ekstra bir adım ekler (render, effect çalışır, state ayarlanır, tekrar render). Bu ekstra adım titremelere, döngülere ve “neden bu eski?” tarzı hatalara yol açar.
Yaygın bir karışıklık: firstName ve lastName var ve fullName'i state'e koyup effect ile ayarlıyorsunuz. Ama fullName bir yan etki (side effect) değildir. Bu türetilmiş veridir. Render sırasında hesaplayın, her zaman eşleşir.
Alışkanlık olarak: UI değerlerini render sırasında (ve bir şey gerçekten pahalıysa useMemo ile) türetin; effect'leri “bir şey yap” işleri için kullanın, “bir şeyi çöz” işleri için değil.
Bağımlılık dizisini şu şekilde düşünün: “Bu değerler değiştiğinde dış dünya ile yeniden senkronize ol.” Bu bir performans hilesi değildir ve uyarıları susturmak için kullanılmaz.
Örnek: userId değiştiğinde kullanıcı detayları çekiyorsanız, userId effect bağımlılık dizisine dahil olmalıdır çünkü bu senkronizasyonu tetiklemesi gerekir. Eğer effect token da kullanıyorsa onu da ekleyin, yoksa eski token ile fetch edebilirsiniz.
İyi bir içgüdü kontrolü: bir effect'i kaldırmak sadece UI'yı yanlış yapacaksa, muhtemelen gerçek bir effect değildi. Eğer kaldırmak bir zamanlayıcıyı durdurmayı, bir aboneliği iptal etmeyi veya bir fetch'i atlamayı engelliyorsa, muhtemelen gerçek bir effect'ti.
En faydalı zihinsel modellerden biri basit: veri ağaç boyunca aşağı akar ve kullanıcı eylemleri yukarı çıkar.
Bir üst bileşen değerleri çocuklara geçirir. Çocuklar aynı değerin iki kopyasına gizlice “sahip” olmamalıdır. Değişiklikleri bir fonksiyon çağırarak isterler ve üst bileşen yeni değere karar verir.
UI'nın iki kısmı aynı konuda anlaşmak zorundaysa, değeri tek bir yerde saklayın ve aşağı verin. Buna “state lifting” denir. Başta ekstra boru döşüyormuş gibi gelse de daha kötü bir problemi önler: birbirinden uzaklaşan iki state ve bunları senkron tutmak için ek hack'ler eklemek.
Örnek: arama kutusu ve sonuç listesi. Eğer input kendi query'sini saklarsa ve liste kendi query'sini saklarsa, sonunda “input X gösteriyor ama liste Y kullanıyor” görürsünüz. Çözüm query'yi bir ebeveynde tutmak, ikisine aşağı vermek ve input'a onChangeQuery(newValue) handler'ı vermektir.
Her zaman lift etmek çözüm değildir. Bir değer sadece bir bileşen içinde önemliyse, orada tutun. State'i kullanıldığı yere yakın tutmak genellikle kodu daha okunur yapar.
Pratik bir sınır:
Kararsızsanız, şu işaretlere bakın: iki bileşen aynı değeri farklı şekillerde gösteriyor; bir yerdeki eylem uzağı etkiliyor; props'ları “ya olur diye” state'e kopyalıyorsunuz; veya iki değeri uyumlu tutmak için effect'ler ekliyorsunuz. Böyle işaretler varsa state'i yukarı taşıyın.
Bu model sohbet tabanlı araçlarla çalışırken de yardımcı olur: her paylaşılan state parçası için tek bir sahibi isteyin, sonra handler'ları yukarı doğru akacak şekilde üretin.
Kafanızda tutabileceğiniz kadar küçük bir özellik seçin. İyi bir örnek aranabilir bir liste ve bir öğeye tıklayınca detayları modal içinde gösterme.
Önce UI parçalarını ve olabilecek olayları çizin. Henüz koda bakmayın. Kullanıcının ne yapabileceğini ve ne görebileceğini düşünün: bir arama input'u, bir liste, seçili satır vurgusu ve bir modal var. Olaylar: arama yazma, öğeye tıklama, modal açma ve modal kapatma.
Şimdi “durumu çizin.” Saklanması gereken birkaç değeri yazın ve kimin sahip olacağını karar verin. Basit bir kural işe yarar: değere ihtiyaç duyan tüm yerlerin en yakın ortak ebeveyni onu sahiplenmelidir.
Bu özellik için saklanan state küçük olabilir: query (string), selectedId (id veya null) ve isModalOpen (boolean). Liste query okur ve öğeleri render eder. Modal detayları göstermek için selectedId okur. Hem liste hem modal selectedId'e ihtiyaç duyuyorsa, onu her ikisinde değil üstte tutun.
Sonra türetilmiş veriyi saklamakla saklanan veriyi ayırın. Filtrelenmiş liste türetilmiş veridir: filteredItems = items.filter(...). Bunu state'te saklamayın çünkü her zaman items ve query'den yeniden hesaplanabilir. Türemiş veri saklamak değerlerin kaymasına yol açar.
Sadece sonra sorun: effect'e ihtiyacımız var mı? Eğer öğeler zaten bellekteyse hayır. Eğer bir query yazınca sonuçlar fetch edilecekse evet. Modal kapandığında bir şey kaydedilecekse evet. Effect'ler senkronizasyon içindir (fetch, save, subscribe), temel UI wiring için değil.
Son olarak birkaç kenar durumu kağıt üzerinde test edin:
selectedId hâlâ geçerli mi?Bunları kağıt üzerinde cevaplayabiliyorsanız, React kodu genellikle doğrudan gelir.
Çoğu React kafa karışıklığı sözdizimsel değildir. Kodunuz kafanızdaki basit hikâyeyle uyuşmayı bıraktığında olur.
Türemiş state saklamak. fullName'i firstName + lastName olduğu halde state'te saklıyorsunuz. Bir alan değişince diğer değişmeyebilir ve UI eski değer gösterir.
Effect döngüleri. Bir effect veri çekiyor, state ayarlıyor ve bağımlılık listesi bunun tekrar çalışmasına sebep oluyor. Semptom tekrarlanan istekler, titreyen UI veya hiç stabil olmayan state'tir.
Stale closure'lar. Bir click handler eski bir değeri okur (eski bir sayaç veya filtre gibi). Semptom “tıkladım ama dünün değerini kullandı.”
Her yerde global state. Her UI detayını global store'a koymak neyin sahibi olduğunu anlamayı zorlaştırır. Semptom bir şeyi değiştirdiğinizde üç ekranın beklenmedik şekilde tepki vermesi.
İç içe nesneleri değiştirmek. Bir nesne veya diziyi yerinde güncellersiniz ve neden UI güncellemediğini sorgularsınız. Semptom “veri değişti ama yeniden render olmadı.”
Somut bir örnek: bir liste için “arama ve sıralama” paneli. Eğer filteredItems'ı state'te saklarsanız, yeni veri geldiğinde items'tan sapma olabilir. Bunun yerine girdileri saklayın (search text, sort choice) ve render sırasında filtrelenmiş listeyi hesaplayın.
Effect'lerde, bunları dış dünyayla senkronize etmek için tutun (fetching, subscription, timer). Eğer bir effect temel UI işi yapıyorsa, genelde onun yerine render veya bir event handler içinde olmalıdır.
Sohbet yoluyla kod üretirken bu hatalar daha hızlı ortaya çıkar çünkü değişiklikler büyük parçalar halinde gelebilir. İyi bir alışkanlık, istekleri sahiplik açısından çerçevelemektir: “Bu değerin gerçek kaynağı neresi?” ve “Bunu saklayabilir miyiz yoksa hesaplayabilir miyiz?”
UI'nız öngörülemez hissetmeye başladığında, nadiren “çok fazla React” sorunudur. Genelde yanlış yerlerde, gereksiz şeyler için çok fazla state vardır.
Başka bir useState eklemeden önce durun ve sorun:
Küçük örnek: arama kutusu, filtre dropdown, liste. Hem query hem filteredItems'ı state'te saklarsanız artık iki gerçek kaynağınız olur. Bunun yerine query ve filter'ı state'te tutun, sonra filteredItems'ı tam listeden render sırasında türetin.
Bu, sohbet araçlarıyla hızlı inşa ederken de önemlidir. Hız iyidir ama sürekli sorun sorun: “State ekledik mi yoksa yanlışlıkla türetilmiş bir değer mi ekledik?” Eğer türetilmişse o state'i silin ve hesaplayın.
Küçük bir ekip bir admin UI inşa ediyor: sipariş tablosu, birkaç filtre ve bir siparişi düzenlemek için dialog. İlk istek belirsiz olabilir: “Filtreler ve bir düzenleme popup'ı ekle.” Bu basit görünse de genelde rastgele state her yere dağılır.
İsteği somutlaştırın: onu state ve olaylara çevirin. “Filtreler” yerine state adlandırın: query, status, dateRange. “Düzenle popup'ı” yerine olayı adlandırın: “kullanıcı bir satırda Düzenle'ye tıklıyor.” Sonra her state parçasının sahibi kim olacak (page, table veya dialog) ve hangi şeylerin türetilmiş olduğu kararını verin.
Koruyucu örnek istemler (bunlar Koder.ai gibi sohbet tabanlı üreticilerde de iyi çalışır):
OrdersPage oluşturun; filters ve selectedOrderId ona ait. OrdersTable filters ile kontrol edilsin ve onEdit(orderId) çağırsın.”visibleOrders'ı orders ve filters'tan türetin. visibleOrders'ı state'e kaydetmeyin.”EditOrderDialog ekleyin; order ve open props olarak alsın. Kaydettiğinde onSave(updatedOrder) çağırıp kapansın.”filters'ı URL'e senkronize etmek için kullanın, satırları hesaplamak için değil.”UI üretildikten veya güncellendikten sonra hızlı bir kontrol yapın: her state değerinin bir sahibi var mı, türetilmiş değerler saklanmamış mı, effect'ler sadece dış dünya ile senkronize ediyor mu (URL, ağ, depolama), ve olaylar props olarak aşağı akıp callback'lerle yukarı mı geliyor?
State öngörülebilir olduğunda yineleme güvenli hale gelir. Tablo düzenini değiştirebilir, yeni bir filtre ekleyebilir veya dialog alanlarını kırpabilirsiniz; hangi gizli state'in kırılacağını tahmin etmek zorunda kalmazsınız.
Hız yalnızca uygulama hâlâ anlaşılır kalıyorsa değerlidir. En basit koruma, bu zihinsel modelleri bir kontrol listesi gibi alıp her özelliğe uygulamaktır.
Her özelliğe aynı şekilde başlayın: ihtiyaç duyduğunuz state'i, onu değiştirebilecek olayları ve kimin sahip olacağını yazın. Eğer “Bu bileşen bu state'e sahip ve bu olaylar onu güncelliyor” diyemiyorsanız, muhtemelen state dağılacak ve yeniden render'lar sürpriz yapacaktır.
Eğer sohbet üzerinden inşa ediyorsanız önce planlama moduyla başlayın. Bileşenleri, state şekillerini ve geçişleri sade dilde tarif edin, sonra kod isteyin. Örnek: “Bir filtre paneli query state'ini güncelliyor; sonuç listesi query'den türetiliyor; bir öğe seçmek selectedId ayarlıyor; kapatmak onu temizliyor.” Bu temiz okunuyorsa, UI üretimi mekanik bir adıma dönüşür.
Eğer Koder.ai (koder.ai) ile React kodu üretiyorsanız, küçük bir sağduyu kontrolü yapmak faydalıdır: her state değeri için bir net sahip, UI state'ten türetilmiş, effect'ler sadece senkronize ediyor ve gerçek kaynağın iki kopyası yok.
Sonra küçük adımlarla yineleyin. State yapısını değiştirmek istiyorsanız (mesela birkaç boolean'dan tek bir status alanına geçmek), önce bir snapshot alın, denemeyi yapın ve eğer zihinsel model bozulduysa geri alın. Daha derin bir inceleme veya devralma gerektiğinde, kaynak kodunu dışa aktarmak durum yapısının hâlâ UI hikâyesini anlatıp anlatmadığını görmeyi kolaylaştırır.
İyi bir başlangıç modeli: UI = f(state, props). Bileşenler DOM'u “düzeltmez”; mevcut verilere göre ekranda ne olması gerektiğini tanımlarlar. Ekran yanlış görünüyorsa DOM'a değil, onu üreten state/props'a bakın.
Props girdilerdir; bir üst bileşenden gelir ve bileşen bunları salt okunur olarak görmelidir. State bellektir; bir bileşenin (veya seçtiğiniz sahibi olan bileşenin) sahip olduğu ve zaman içinde değişen veridir. Bir değer paylaşılmalıysa, onu yukarı taşıyın ve props olarak aşağı verin.
Bir re-render, React'in bileşen fonksiyonunuzu yeniden çalıştırdığı ve bir sonraki UI tanımını hesapladığı anlamına gelir. Bu otomatik olarak bütün sayfanın yeniden boyandığı anlamına gelmez. React sonra gerçek DOM'u en küçük değişiklik setiyle günceller.
Çünkü state güncellemeleri zamanlanır, anında atama değiller. Eğer yeni değer önceki değere bağlıysa, olası eski değere güvenmemek için updater formunu kullanın:
setCount(c => c + 1)Bu, birden fazla güncelleme sıraya alınsa bile doğru kalır.
Mevcut girdilerden hesaplayabileceğiniz hiçbir şeyi saklamayın. Girdileri saklayın, geri kalanını render sırasında türetin.
Örnekler:
items, filtervisibleItems = items.filter(...)Bu, değerlerin uyumsuz hale gelmesini önler.
Effect'leri React'in kontrol etmediği şeylerle senkronize olmak için kullanın: fetching, abonelikler, zamanlayıcılar, tarayıcı API'leri veya imperatif DOM işleri.
Sadece state'ten UI değerleri hesaplamak için effect kullanmayın—bunları render sırasında (ve gerçekten pahalıysa useMemo ile) hesaplayın.
Bağımlılık dizisini şu şekilde düşünün: bir tetikleyici listesi: “bu değerler değiştiğinde dış dünya ile tekrar senkronize ol.” Effect'in okuduğu her reaktif değeri dahil edin.
Bir şeyi dışarıda bırakırsanız eski verilerle işlem yapabilirsiniz (ör. eski userId veya token). Yanlış şeyler eklemek döngülere yol açabilir—çoğu zaman bunun işaretidir: effect'in yaptığı iş aslında event'lerde veya render'da olmalıdır.
Eğer UI'nın iki kısmı her zaman aynı şey gösteriyorsa, state'i en yakın ortak ebeveyne koyun, değeri aşağı verin ve değişiklikleri geri bildirmek için callback'ler gönderin.
Hızlı test: aynı değeri iki bileşende kopyalayıp “eşitlemek için” effect'ler yazıyorsanız, o state muhtemelen tek bir sahibi olmalı.
Genellikle bir handler'ın önceki render'dan alınmış eski bir değeri “yakalamış” olmasından kaynaklanır. Yaygın çözümler:
setX(prev => ...)Eğer bir tıklama “dünkü değeri” kullanıyorsa, muhtemelen stale closure vardır.
Küçük bir planla başlayın: bileşenler, state sahipleri ve olaylar. Sonra kodu küçük yamalar olarak üretin (bir state alanı ekle, bir handler ekle, bir değer render'da türet) büyük yeniden yazımlardan kaçının.
Chat tabanlı bir oluşturucu kullanıyorsanız (ör. Koder.ai), şunları isteyin:
Bu, üretilen kodun React zihinsel modeliyle uyumlu kalmasını sağlar.