State: Bir Bileşenin Hafızası
Bileşenler, etkileşimin bir sonucu olarak ekranda olanı değiştirmeye sıklıkla ihtiyaç duyarlar. Forma yazı yazmak, giriş alanını güncellemelidir, resim karuselinde “sonraki”ye tıklamak gösterilen resmi değiştirmelidir, “satın al” düğmesine tıklamak bir ürünü alışveriş sepetine koymalıdır. Bileşenler şeyleri “hatırlamalıdır”: mevcut girdi değeri, mevcut resim, alışveriş sepeti. React’te, bileşene özgü bu tür bellek state olarak adlandırılır.
Bunları öğreneceksiniz
useStateHook’u ile state değişkeni nasıl ekleniruseStateHook’unun döndürdüğü değer çifti- Birden fazla state değişkeni nasıl eklenir
- Neden state’in yerel olarak adlandırıldığı
Normal bir değişken yeterli olmadığında
İşte bir heykel resmini oluşturan bir bileşen. “Sonraki” düğmesine tıklanarak index değişkeni 1, ardından 2 ve benzeri şekilde değiştirilerek bir sonraki heykel gösterilmelidir. Ancak bu çalışmayacaktır (deneyebilirsiniz!):
import { sculptureList } from './data.js'; export default function Gallery() { let index = 0; function handleClick() { index = index + 1; } let sculpture = sculptureList[index]; return ( <> <button onClick={handleClick}> Sonraki </button> <h2> <i>{sculpture.name} </i> by {sculpture.artist} </h2> <h3> ({index + 1} of {sculptureList.length}) </h3> <img src={sculpture.url} alt={sculpture.alt} /> <p> {sculpture.description} </p> </> ); }
handleClick olay yöneticisi bir yerel değişken olan index’i güncelliyor. Ancak, iki şey bu değişikliğin görünür olmasını engelliyor:
- Yerel değişkenler renderlar arasında kalıcı değildir. React bu bileşeni ikinci kez renderladığında, herhangi bir yerel değişiklik göz önünde bulundurulmaz ve bileşen sıfırdan yeniden renderlanır.
- Yerel değişkenlere yapılan değişiklikler renderı tetiklemez. React, bileşeni yeni verilerle yeniden render etmesi gerektiğini fark etmez.
Yeni verilerle bir bileşeni güncellemek için, iki şeyin yapılması gerekir:
- Renderlar arasında verileri korumak.
- Bileşeni yeni verilerle yeniden render etmesi için React’i tetiklemek.
useState Hook’u bu iki şeyi sağlar:
- Renderlar arasında verileri saklamak için bir state değişkeni.
- Değişkeni güncellemek ve React’in bileşeni tekrar render etmesini tetiklemek için bir state setter fonksiyonu.
State değişkeni ekleme
Bir state değişkeni eklemek için, dosyanın üst kısmında React’ten useState öğesini içe aktarın:
import { useState } from 'react';Ardından, bu satırı:
let index = 0;bununla değiştirin
const [index, setIndex] = useState(0);index bir state değişkeni ve setIndex ise bir setter fonksiyonudur.
Buradaki
[ve]sözdizimine array destructuring denir ve bir diziden değerleri okumanızı sağlar.useStatetarafından döndürülen dizi her zaman tam olarak iki öğeye sahiptir.
handleClick içinde birlikte bu şekilde çalışırlar:
function handleClick() {
setIndex(index + 1);
}Artık “Sonraki” düğmesine tıklamak mevcut heykeli değiştirir:
import { useState } from 'react'; import { sculptureList } from './data.js'; export default function Gallery() { const [index, setIndex] = useState(0); function handleClick() { setIndex(index + 1); } let sculpture = sculptureList[index]; return ( <> <button onClick={handleClick}> Sonraki </button> <h2> <i>{sculpture.name} </i> by {sculpture.artist} </h2> <h3> ({index + 1} of {sculptureList.length}) </h3> <img src={sculpture.url} alt={sculpture.alt} /> <p> {sculpture.description} </p> </> ); }
İlk Hook’unuz ile tanışın
React’te, useState ve “use” ile başlayan diğer tüm fonksiyonlar Hook olarak adlandırılır.
Hook’lar yalnızca React rendering işlemi sırasında kullanılabilen özel fonksiyonlardır (bir sonraki sayfada daha ayrıntılı olarak ele alacağız). Bunlar farklı React özelliklerini “bağlamaya” izin verirler.
State bu özelliklerden sadece biri, ancak diğer Hook’larla daha sonra tanışacaksınız.
useState’in’ anatomisi
useState fonksiyonunu çağırdığınızda, React’e bu bileşenin bir şeyleri hatırlamasını istediğinizi söylüyorsunuz:
const [index, setIndex] = useState(0);Bu örnekte, React’in indexi hatırlamasını istiyorsunuz.
useState’e verilen tek argument, state variable’ınızın initial value’sudur. Bu örnekte, index’in initial value’su useState(0) ile 0 olarak set edilir.
Bileşeniniz her render edildiğinde, useState size iki değer içeren bir dizi verir:
- Değerinizi saklayan state değişkeni (
index). - State değişkenini güncelleyebilen ve React’in bileşeni yeniden renderlaması için tetikleyen state setter fonksiyonu (
setIndex).
İşte bunun işleyişi:
const [index, setIndex] = useState(0);- Bileşeniniz ilk kez render edilir.
useState’eindexbaşlangıç değeri olarak0geçtiğinizden,[0, setIndex]olarak geri dönecektir. React,0değerinin en son state değeri olduğunu hatırlar. - State’i güncellersiniz. Bir kullanıcı butona tıkladığında,
setIndex(index + 1)çağırır.indexdeğeri0olduğu içinsetIndex(1)çağrılır. Bu, React’eindex’in artık1olduğunu hatırlamasını söyler ve başka bir render işlemini tetikler. - Bileşeninizin ikinci render edilişi. React hala
useState(0)’ı görür, ancak Reactindex’in artık1olarak ayarlandığını hatırladığıdan,[1, setIndex]olarak geri döner. - Ve böyle devam eder!
Bir bileşene birden fazla state değişkeni verme
Bir bileşende istediğiniz kadar çok sayıda farklı tipte state değişkeni olabilir. Bu bileşende, bir index sayısı ve “Detayları göster”e tıkladığınızda değiştirilen bir boolean showMore değeri:
import { useState } from 'react'; import { sculptureList } from './data.js'; export default function Gallery() { const [index, setIndex] = useState(0); const [showMore, setShowMore] = useState(false); function handleNextClick() { setIndex(index + 1); } function handleMoreClick() { setShowMore(!showMore); } let sculpture = sculptureList[index]; return ( <> <button onClick={handleNextClick}> Sonraki </button> <h2> <i>{sculpture.name} </i> by {sculpture.artist} </h2> <h3> ({index + 1} of {sculptureList.length}) </h3> <button onClick={handleMoreClick}> Detayları {showMore ? 'Gizle' : 'Göster'} </button> {showMore && <p>{sculpture.description}</p>} <img src={sculpture.url} alt={sculpture.alt} /> </> ); }
Bu örnekte olduğu gibi index ve showMore gibi state’ler birbirleriyle ilişkisiz olduğunda, birden fazla state değişkenine sahip olmak iyi bir fikirdir. Ancak iki state değişkenini sık sık birlikte değiştirdiğinizi fark ederseniz, bunları tek bir değişkende birleştirmek daha pratik olabilir. Örneğin, çok sayıda alana sahip bir formunuz varsa, alan başına state değişkeni yerine bir nesneyi tutan tek bir state değişkenine sahip olmak daha uygundur. Daha fazla ipucu için Choosing the State Structure bölümünü okuyun.
Derinlemesine İnceleme
useState çağrısının hangi state değişkenine referans verdiği hakkında herhangi bir bilgi almadığını fark etmiş olabilirsiniz. useState’e geçilen bir “tanımlayıcı” yoktur, peki hangi state değişkenini döndüreceğini nasıl bilir? Fonksiyonlarınızı ayrıştırmak gibi bir sihre mi güveniyor? Cevap hayır.
Bunun yerine, kısa sözdizimlerini etkinleştirmek için Hook’lar aynı bileşenin her render edilişinde sabit bir çağrı sırasına dayanır. Bu pratikte iyi çalışır, çünkü yukarıdaki kuralı izlerseniz (“Hook’ları yalnızca en üst düzeyde çağırın”), Hook’lar her zaman aynı sırada çağrılacaktır. Ek olarak bir linter eklentisi çoğu hatayı yakalar.
Dahili olarak, React her bileşen için bir state çifti dizisi tutar. Ayrıca, render edilmeden önce 0 olarak ayarlanan mevcut çift indeksini de tutar. Her useState’i çağırdığınızda, React size bir sonraki state çiftini verir ve indeksi artırır. Bu mekanizma hakkında daha fazla bilgi için React Hooks: Not Magic, Just Arrays yazısını okuyabilirsiniz.
Bu örnekte React kullanılmıyor ancak useStatein dahili olarak nasıl çalıştığı hakkında bir fikir verir:
let componentHooks = []; let currentHookIndex = 0; // useState'nın React içinde nasıl çalıştığı (basitleştirilmiş). function useState(initialState) { let pair = componentHooks[currentHookIndex]; if (pair) { // Bu ilk render değil, // dolayısıyla state çifti zaten var. // Onu döndür ve bir sonraki Hook çağrısı için hazırla. currentHookIndex++; return pair; } // Bu ilk render, // state çifti oluştur ve depola. pair = [initialState, setState]; function setState(nextState) { // Kullanıcı state değişikliği talep ettiğinde, // yeni değeri çiftin içine yerleştir. pair[0] = nextState; updateDOM(); } // Gelecekteki renderlar için çifti depola // ve bir sonraki Hook çağrısı için hazırla. componentHooks[currentHookIndex] = pair; currentHookIndex++; return pair; } function Gallery() { // Her useState() çağrısı bir sonraki çifti alacaktır. const [index, setIndex] = useState(0); const [showMore, setShowMore] = useState(false); function handleNextClick() { setIndex(index + 1); } function handleMoreClick() { setShowMore(!showMore); } let sculpture = sculptureList[index]; // Bu örnek React kullanmadığından // JSX yerine bir çıktı nesnesi geri döndürür. return { onNextClick: handleNextClick, onMoreClick: handleMoreClick, header: `${sculpture.name} by ${sculpture.artist}`, counter: `${index + 1} of ${sculptureList.length}`, more: `$Detayları {showMore ? 'Gizle' : 'Göster'}`, description: showMore ? sculpture.description : null, imageSrc: sculpture.url, imageAlt: sculpture.alt }; } function updateDOM() { // Bileşeni oluşturmadan önce // mevcut Hook dizinini sıfırla. currentHookIndex = 0; let output = Gallery(); // Çıktıya uygun olarak DOM'u güncelle. // Bu kısım React tarafından sizin için yapılır. nextButton.onclick = output.onNextClick; header.textContent = output.header; moreButton.onclick = output.onMoreClick; moreButton.textContent = output.more; image.src = output.imageSrc; image.alt = output.imageAlt; if (output.description !== null) { description.textContent = output.description; description.style.display = ''; } else { description.style.display = 'none'; } } let nextButton = document.getElementById('nextButton'); let header = document.getElementById('header'); let moreButton = document.getElementById('moreButton'); let description = document.getElementById('description'); let image = document.getElementById('image'); let sculptureList = [{ name: 'Homenaje a la Neurocirugía', artist: 'Marta Colvin Andrade', description: 'Although Colvin is predominantly known for abstract themes that allude to pre-Hispanic symbols, this gigantic sculpture, an homage to neurosurgery, is one of her most recognizable public art pieces.', url: 'https://react.dev/images/docs/scientists/Mx7dA2Y.jpg', alt: 'İki çapraz elin, parmak uçlarında insan beynini nazikçe tuttuğu bronz bir heykel.' }, { name: 'Floralis Genérica', artist: 'Eduardo Catalano', description: 'Bu devasa (75 ft. veya 23 m) gümüş çiçek Buenos Aires’te yer alır. Akşamları veya güçlü rüzgarlar estiğinde taç yapraklarını kapatacak, sabahları ise açacak şekilde tasarlanmıştır.', url: 'https://react.dev/images/docs/scientists/ZF6s192m.jpg', alt: 'Yansıtıcı, ayna benzeri taç yaprakları ve güçlü erkek organları olan devasa metalik bir çiçek heykeli.' }, { name: 'Eternal Presence', artist: 'John Woodrow Wilson', description: 'Wilson; eşitlik, sosyal adalet ve insanlığın temel ve ruhani nitelikleriyle ilgilenmesiyle biliniyordu. Bu büyük (7 ft. veya 2,13 m) bronz eser, onun "evrensel insanlık duygusuyla harmanlanmış sembolik bir Siyah varlık" olarak tanımladığı şeyi temsil eder.', url: 'https://react.dev/images/docs/scientists/aTtVpES.jpg', alt: 'Bir insan başını tasvir eden heykel, her zaman var olan ve ağırbaşlı bir izlenim verir. Sakinlik ve huzur yayar.' }, { name: 'Moai', artist: 'Bilinmeyen Sanatçı', description: 'Paskalya Adası’nda bulunan, erken dönem Rapa Nui halkı tarafından oluşturulmuş 1.000 adet moai veya günümüze ulaşmış anıtsal heykel vardır. Bazılarına göre bunlar tanrılaştırılmış ataları temsil ediyordu.', url: 'https://react.dev/images/docs/scientists/RCwLEoQm.jpg', alt: 'Orantısız derecede büyük başlara ve ciddi yüz ifadelerine sahip üç anıtsal taş büst.' }, { name: 'Blue Nana', artist: 'Niki de Saint Phalle', description: 'Nana’lar, kadınlık ve anneliğin sembolleri olan zafer kazanmış varlıklardır. Başlangıçta Saint Phalle, Nana’lar için kumaş ve buluntu nesneler kullandı; daha sonra daha canlı bir etki elde etmek için polyesteri dahil etti.', url: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg', alt: 'Renkli bir kostüm içinde neşe saçan, oyunbaz şekilde dans eden büyük bir kadın figürünün mozaik heykeli.' }, { name: 'Ultimate Form', artist: 'Barbara Hepworth', description: 'Bu soyut bronz heykel, Yorkshire Sculpture Park’ta yer alan The Family of Man serisinin bir parçasıdır. Hepworth, dünyanın birebir temsillerini oluşturmak yerine insanlardan ve manzaralardan ilham alan soyut formlar geliştirmeyi seçti.', url: 'https://react.dev/images/docs/scientists/2heNQDcm.jpg', alt: 'Üst üste yerleştirilmiş üç öğeden oluşan ve bir insan figürünü hatırlatan uzun bir heykel.' }, { name: 'Cavaliere', artist: 'Lamidi Olonade Fakeye', description: "Dört kuşak ahşap oymacısının soyundan gelen Fakeye’nin çalışmaları, geleneksel ve çağdaş Yoruba temalarını harmanladı.", url: 'https://react.dev/images/docs/scientists/wIdGuZwm.png', alt: 'Desenlerle süslenmiş bir atın üzerinde, odaklanmış yüz ifadeli bir savaşçıyı tasvir eden ayrıntılı bir ahşap heykel.' }, { name: 'Big Bellies', artist: 'Alina Szapocznikow', description: "Szapocznikow, parçalanmış beden heykellerini gençliğin ve güzelliğin kırılganlığı ile geçiciliğine dair bir metafor olarak kullanmasıyla bilinir. Bu heykel, üst üste yerleştirilmiş iki oldukça gerçekçi büyük göbeği tasvir eder; her biri yaklaşık beş fit (1,5 m) uzunluğundadır.", url: 'https://react.dev/images/docs/scientists/AlHTAdDm.jpg', alt: 'Heykel, klasik heykellerdeki göbeklerden oldukça farklı olan bir kıvrım şelalesini andırır.' }, { name: 'Terracotta Army', artist: 'Bilinmeyen Sanatçı', description: 'Terracotta Army, Çin’in ilk İmparatoru Qin Shi Huang’ın ordularını tasvir eden pişmiş toprak heykellerden oluşan bir koleksiyondur. Ordu; 8.000’den fazla asker, 520 atlı 130 savaş arabası ve 150 süvari atından oluşuyordu.', url: 'https://react.dev/images/docs/scientists/HMFmH6m.jpg', alt: 'Her biri kendine özgü yüz ifadesine ve zırha sahip, ciddi görünümlü savaşçılardan oluşan 12 pişmiş toprak heykel.' }, { name: 'Lunar Landscape', artist: 'Louise Nevelson', description: 'Nevelson, New York City enkazından nesneler toplaması ve bunları daha sonra anıtsal yapılara dönüştürmesiyle biliniyordu. Bu eserde; yatak direği, jonglör labutu ve koltuk parçası gibi birbirinden farklı parçaları kullandı, bunları kutuların içine çivileyip yapıştırarak Kübizmin mekan ve form üzerindeki geometrik soyutlama etkisini yansıttı.', url: 'https://react.dev/images/docs/scientists/rN7hY6om.jpg', alt: 'Tek tek öğelerin ilk bakışta ayırt edilemediği siyah mat bir heykel.' }, { name: 'Aureole', artist: 'Ranjani Shettar', description: 'Shettar geleneksel ile moderni, doğal olan ile endüstriyel olanı birleştirir. Sanatı, insan ve doğa arasındaki ilişkiye odaklanır. Eserleri hem soyut hem figüratif açıdan etkileyici, yer çekimine meydan okuyan ve "beklenmedik malzemelerin ince bir sentezi" olarak tanımlanmıştır.', url: 'https://react.dev/images/docs/scientists/okTpbHhm.jpg', alt: 'Beton duvara monte edilmiş ve zemine doğru inen, soluk renkli tel benzeri bir heykel. Hafif görünür.' }, { name: 'Hippos', artist: 'Taipei Hayvanat Bahçesi', description: 'Taipei Hayvanat Bahçesi, oyun oynayan suya batmış hipopotamları içeren bir Hippo Square yaptırdı.', url: 'https://react.dev/images/docs/scientists/6o5Vuyu.jpg', alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.' }]; // Kullanıcı arayüzünü ilk state ile eşleştir. updateDOM();
React’i kullanmak için bunu anlamak zorunda değilsiniz, ancak bu sizin için yararlı bir zihinsel model olabilir.
State izole edilmiştir ve özeldir
State, ekrandaki bir bileşen örneği için yereldir. Başka bir deyişle, aynı bileşeni iki kez render ederseniz, her bir kopya tamamen izole edilmiş state’e sahip olacaktır Birini değiştirmek diğerini etkilemeyecektir.
Bu örnekte, önceki örnekteki Gallery bileşeni çalışma mantığı değiştirilmeden iki kez render edilir. Galerilerin her birinin içindeki düğmelere tıklamayı deneyin. State’lerinin bağımsız olduğuna dikkat edin:
import Gallery from './Gallery.js'; export default function Page() { return ( <div className="Page"> <Gallery /> <Gallery /> </div> ); }
Bu, state’i modülünüzün en üstünde bildirebileceğiniz normal değişkenlerden farklı kılan şeydir. State belirli bir fonksiyon çağrısına veya koddaki bir yere bağlı değildir, ancak ekrandaki belirli bir yere “yereldir”. İki <Gallery /> bileşeni oluşturdunuz, bu nedenle state’leri ayrı ayrı saklanır.
Ayrıca Page bileşeninin Gallery state’i hakkında hiçbir şey “bilmediğine” ve hatta herhangi bir state’e sahip olup olmadığına dikkat edin. Prop’ların aksine, state, onu bildiren bileşene tamamen özeldir. Üst bileşen onu değiştiremez. Bu, bileşenlerin geri kalanını etkilemeden herhangi bir bileşene state eklemenize veya kaldırmanıza olanak tanır.
Peki ya her iki galerinin de state’lerinin senkronize olmasını istiyorsanız? React’te bunu yapmanın doğru yolu, alt bileşenlerden state’i kaldırmak ve en yakın paylaşılan ebeveynlerine eklemektir. Sonraki birkaç sayfa tek bir bileşenin state’ini düzenlemeye odaklanacak, ancak bu konuya Sharing State Between Components bölümünde geri döneceğiz.
Özet
- Bir bileşenin render işlemleri arasında bazı bilgileri “hatırlaması” gerektiğinde bir state değişkeni kullanın.
- State değişkenleri
useStateHook`u çağrılarak bildirilir. - Hook’lar
useile başlayan özel fonksiyonlardır. State gibi React özelliklerine “bağlanmanızı (hook into)” sağlarlar. - Hook’lar, size import’ları hatırlatabilir: koşulsuz olarak çağrılmalıdırlar.
useStatede dahil Hook’ları çağırmak, yalnızca bir bileşenin üst seviyesinde veya başka bir Hook’ta geçerlidir. useStateHook’u bir çift değer döndürür: mevcut state ve onu güncelleyecek fonksiyon.- Birden fazla state değişkeniniz olabilir. Dahili olarak, React bunları sıralarına göre eşleştirir.
- State bileşene özeldir. Eğer iki yerde render ederseniz, her kopya kendi state’ini oluşturur.
Problem 1 / 4: Galeriyi tamamlayın
Son heykelde “Sonraki” tuşuna bastığınızda kod çöküyor. Çökmeyi önlemek için mantığı düzeltin. Bunu olay yöneticisine ekstra mantık ekleyerek veya işlem mümkün olmadığında düğmeyi devre dışı bırakarak yapabilirsiniz.
Çökmeyi düzelttikten sonra, bir önceki heykeli gösteren “Önceki” düğmesi ekleyin. İlk heykelde çökmemesi gerekir.
import { useState } from 'react'; import { sculptureList } from './data.js'; export default function Gallery() { const [index, setIndex] = useState(0); const [showMore, setShowMore] = useState(false); function handleNextClick() { setIndex(index + 1); } function handleMoreClick() { setShowMore(!showMore); } let sculpture = sculptureList[index]; return ( <> <button onClick={handleNextClick}> Sonraki </button> <h2> <i>{sculpture.name} </i> by {sculpture.artist} </h2> <h3> ({index + 1} of {sculptureList.length}) </h3> <button onClick={handleMoreClick}> Detayları {showMore ? 'Gizle' : 'Göster'} </button> {showMore && <p>{sculpture.description}</p>} <img src={sculpture.url} alt={sculpture.alt} /> </> ); }