useState
useState
, bileşeninize state değişkeni eklemenizi sağlayan bir React Hook’udur.
const [state, setState] = useState(initialState)
Referans
useState(initialState)
Bir state değişkeni bildirmek için bileşeninizin en üstünde useState
çağırın.
import { useState } from 'react';
function MyComponent() {
const [age, setAge] = useState(28);
const [name, setName] = useState('Taylor');
const [todos, setTodos] = useState(() => createTodos());
// ...
Ortak düşünce, dizi yapı çözmeyi (array destructuring) kullanarak state değişkenlerini [something, setSomething]
olarak adlandırmaktır.
Aşağıda daha fazla örnek bulabilirsiniz.
Parametreler
initialState
: Başlangıçta state’in alacağı değerdir. Herhangi bir türden bir değer olabilir ancak fonksiyonlar için özel bir davranış vardır. Bu argüman ilk render’dan sonra görmezden gelinir.initialState
olarak bir fonksiyon iletirseniz, bu fonksiyona başlatıcı fonksiyon olarak davranılacaktır. Saf olmalıdır, argüman olmamalıdır ve herhangi bir türden değer döndürebilmelidir. React, bileşeni başlatırken başlatıcı fonksiyonunuzu çağıracak ve döndürülen değeri başlangıç state’i olarak saklayacaktır. Aşağıdaki örneği inceleyin.
Döndürülenler
useState
her zaman iki değere sahip bir dizi döndürür.
- Şu anki state. İlk render sırasında, ilettiğiniz
initialState
değeri ile aynıdır. set
fonksiyonu state’i başka bir değer ile güncellemenizi ve yeniden render tetiklemenizi sağlar.
Uyarılar
useState
bir Hook’tur, bu yüzden sadece bileşeninizin üst seviyesinde ya da kendi Hook’larınızda çağırabilirsiniz. Döngülerin ya da koşullu ifadelerin içinde çağıramazsınız. Eğer buna ihtiyacınız varsa, yeni bir bileşen çıkarın ve state’i o bileşene taşıyın.- Strict Modda React, kazara oluşan saf olmayan şeyleri bulmanıza yardımcı olmak için başlatıcı fonksiyonunuzu iki defa çağıracaktır. Bu sadece geliştirme sırasında görülen bir davranıştır ve son ürünü etkilemez. Eğer başlatıcı fonksiyonunuz saf ise (ki öyle olmalıdır), bu olması gereken davranışı etkilememelidir. Yapılan çağrılardan birinin sonucu görmezden gelinecektir.
setSomething(nextState)
gibi set
fonksiyonları
useState
tarafından döndürülen set
fonksiyonu state’i başka bir değere güncellemenizi ve yeniden render tetiklemenizi sağlar. Bir sonraki state’i direkt olarak ya da önceki state’ten hesaplayan bir fonksiyon iletebilirsiniz:
const [name, setName] = useState('Edward');
function handleClick() {
setName('Taylor');
setAge(a => a + 1);
// ...
Parametreler
nextState
: State’in olmasını istediğiniz değerdir. Herhangi bir türden değer olabilir ama fonksiyonlar için özel bir davranış vardır.- Eğer
nextState
olarak fonksiyon iletirseniz, o fonksiyon güncelleyici fonksiyon olarak görev alacaktır. Saf olmak zorundadır, bekleme durumunu tek argümanı olarak almalı ve bir sonraki state’i döndürmelidir. React, güncelleyici fonksiyonunuzu sıraya koyacaktır ve bileşeninizi yeniden render edecektir. Bir sonraki render sırasında React, sıradaki güncelleyicilerin hepsini bir önceki state’e uygulayarak bir sonraki state’i hesaplayacaktır. Aşağıdaki örneği inceleyin.
- Eğer
Döndürülenler
set
fonksiyonlarının dönüş değeri yoktur.
Uyarılar
-
set
fonksiyonu state değişkenini sadece sonraki render için günceller. Eğer state değişkeniniset
fonksiyonunu çağırdıktan sonra okursanız, hala çağrınızdan önce ekranda gördüğünüz değeri alacaksınız. -
Eğer sağladığınız yeni değer şu anki
state
değeri ile aynıysa, ki buObject.is
karşılaştırması ile belirlenir, React bileşeni ve alt elemanlarını yeniden render etmeyecektir. Bu bir optimizasyon işlemidir. Her ne kadar bazı durumlarda React’in alt elemanları atlamadan önce bileşeninizi çağırması gerekse de bu durum kodunuzu etkilememelidir. -
React state güncellemelerini toplu halde(batches) yapar. React, ekranı tüm olay yöneticileri çalıştıktan ve
set
fonksyionlarını çağırdıktan sonra günceller. Böylelikle tek bir olay sırasında olacak birden fazla yeniden render engellenmiş olur. Nadiren de olsa, örneğin DOM’a erişmek istediğinizde, React’ı ekranı erken güncellemeye zorlamak içinflushSync
kullanabilirsiniz. -
The
set
function has a stable identity, so you will often see it omitted from Effect dependencies, but including it will not cause the Effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. Learn more about removing Effect dependencies. -
Render sırasında
set
fonksiyonu yalnızca mevcut render edilen bileşenin içinde çağırılabilir. React, bileşenin çıktısını görmezden gelecektir ve hemen yeni state ile birlikte render etmeyi deneyecektir. Bu modele nadiren ihtiyaç duyulur ama bunu önceki render’lardan gelen bilgileri saklamak için kullanabilirsiniz. Aşağıdaki örneği inceleyin. -
Strict Modda React, kazara oluşan saf olmayan şeyleri bulmanıza yardımcı olmak için güncelleyici fonksiyonunuzu iki defa çağıracaktır. Bu sadece geliştirme sırasında görülen bir davranıştır ve son ürünü etkilemez. Eğer güncelleyici fonksiyonunuz saf ise (ki öyle olmalı), bu olması gereken davranışı etkilememelidir. Yapılan çağrılardan birinin sonucu görmezden gelinecektir.
Kullanım
Bileşene state ekleme
Bir ya da birden fazla state değişkeni bildirmek için bileşeninizin üst seviyesinde useState
’i çağırın.
import { useState } from 'react';
function MyComponent() {
const [age, setAge] = useState(42);
const [name, setName] = useState('Taylor');
// ...
Ortak düşünce, dizi yapı çözmeyi (destructuring) kullanarak state değişkenlerini [something, setSomething]
olarak adlandırmaktır.
useState
her zaman iki değere sahip bir dizi döndürür:
- Bu state değişkeninin şu anki state’i, başlangıçta belirttiğiniz başlangıç state’ine eşitttir.
set
fonksiyonu herhangi bir etkileşim sonucu state’i başka bir değerle değiştirmenizi sağlar.
Ekranda olanı güncellemek için, set
fonksiyonunu sonraki herhangi bir state ile çağırın:
function handleClick() {
setName('Robin');
}
React sonraki state’i saklayacaktır, bileşeninizi yeni değerler ile render edecektir ve kullanıcı arayüzünü güncelleyecektir.
Örnek 1 / 4: Sayaç (sayı)
Bu örnekte count
state değişkeni bir sayı tutmaktadır. Butona tıklamak bu sayıyı artırır.
import { useState } from 'react'; export default function Counter() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <button onClick={handleClick}> Bana {count} defa tıkladın </button> ); }
State’i bir önceki state’e göre güncelleme
Varsayalım age
state’i 42
olsun. Bu yönetici setAge(age + 1)
fonksiyonunu üç defa çağırır:
function handleClick() {
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
}
Ancak bir tıklamadan sonra age
değeri 45
yerine 43
olacak! Bunun nedeni ise set
fonksiyonunu çağırmanın zaten çalışmakta olan kodda age
state değişkenini güncellememesidir. Yani her setAge(age + 1)
çağrısı setAge(43)
olur.
Bu problemi çözmek için setAge
’e bir sonraki state yerine güncelleyici fonksiyon iletebilirsiniz:
function handleClick() {
setAge(a => a + 1); // setAge(42 => 43)
setAge(a => a + 1); // setAge(43 => 44)
setAge(a => a + 1); // setAge(44 => 45)
}
Burada, a => a + 1
sizin güncelleyici fonksiyonunuzdur. Bekleyen state’i alır ve ondan bir sonraki state’i hesaplar.
React güncelleyici fonksiyonlarınızı sıraya koyar. Daha sonra, sonraki render sırasında, bu fonksiyonları aynı sırada çağıracaktır:
a => a + 1
fonksiyonu42
sayısını bekleyen state olarak alacaktır ve sonraki state olarak43
döndürecektir.a => a + 1
fonksiyonu43
sayısını bekleyen state olarak alacaktır ve sonraki state olarak44
döndürecektir.a => a + 1
fonksiyonu44
sayısını bekleyen state olarak alacaktır ve sonraki state olarak45
döndürecektir.
Sırada bekleyen başka güncelleme olmadığından dolayı React 45
sayısını güncel state olarak saklayacaktır.
Ortak düşünce, bekleyen state argümanını state değişkeni adının ilk harfi olarak adlandırmaktır; örneğin age
için a
kullanmak. Ancak, daha açıklayıcı olmasını istiyorsanız prevAge
ya da başka bir şey kullanabilirsiniz.
React, geliştirme sırasında güncelleyici fonksiyonlarınızın saf olduğunu doğrulamak için onları iki defa çağırır.
Derinlemesine İnceleme
Eğer değiştirdiğiniz state bir önceki state’ten hesaplanıyorsa kodunuzu her zaman setAge(a => a + 1)
olarak yazmanız size tavsiye edilmiş olabilir. Bunda bir sorun yoktur ama her zaman gerekli değildir.
Pek çok durumda bu iki yaklaşım arasında bir fark yoktur. React, tıklamalar gibi kasıtlı olarak yapılmış kullanıcı aksiyonları için age
state değişkeninin bir sonraki tıklamadan önce güncellendiğine emin olur. Bu, tıklama yöneticisinin, olay yöneticisinin başlangıcında “eski” bir age
değişkeni görme riski olmadığı anlamına gelir.
Ancak, aynı olay içinde birden fazla güncelleme yaparsanız, güncelleyiciler yardımcı olabilir. Ayrıca state değişkenine erişmenin sakıncalı olduğu durumlarda da faydalıdırlar (bu durumlarla yeniden render’ları optimize etmeye çalışırken karşılaşabilirsiniz).
Kod olarak kalabılık söz dizimi yerine tutarlığı tercih ediyorsanız, değiştirdiğiniz state bir önceki state’ten hesaplanıyorsa her zaman güncelleyici yazmak mantıklı olacaktır. Eğer state başka bir state değişkeninin önceki state’inden hesaplanıyorsa, güncelleyicileri bir nesne içine koyabilir ve reducer kullanabilirsiniz.
Örnek 1 / 2: Güncelleyici fonksiyonu iletme
Bu örnek güncelleyici fonksiyonu iletmektedir bu yüzden “+3” butonu çalışır.
import { useState } from 'react'; export default function Counter() { const [age, setAge] = useState(42); function increment() { setAge(a => a + 1); } return ( <> <h1>Yaşınız: {age}</h1> <button onClick={() => { increment(); increment(); increment(); }}>+3</button> <button onClick={() => { increment(); }}>+1</button> </> ); }
State’teki nesneleri ve dizileri güncelleme
State içine nesneleri ve dizileri koyabilirsiniz. React’te, state salt-okunur olarak kabul edilir bu yüzden mevcut nesnelerinizi mutasyona uğratmak yerine değiştirmelisiniz. Örneğin, state’inizde bir form
nesnesi varsa, onu mutasyona uğratmayın:
// 🚩 State'teki nesneyi böyle mutasyona uğratmayın:
form.firstName = 'Taylor';
Onun yerine tüm nesneyi yenisiyle değiştirin:
// ✅ State'i yeni bir nesne ile değiştirin
setForm({
...form,
firstName: 'Taylor'
});
Daha fazla bilgi için bu sayfaları okuyun: state içindeki nesneleri güncelleme ve state içindeki dizileri güncelleme.
Örnek 1 / 4: Form (nesne)
Bu örnekte form
state değişkeni bir nesne tutmaktadır. Her input’un tüm formun bir sonraki state’i ile birlikte setForm
fonksiyonunu çağıran bir yöneticisi vardır. { ...form }
spread sözdizimi state nesnesini mutasyona uğratmak yerine değiştirilmesini sağlar.
import { useState } from 'react'; export default function Form() { const [form, setForm] = useState({ firstName: 'Barbara', lastName: 'Hepworth', email: 'bhepworth@sculpture.com', }); return ( <> <label> Ad: <input value={form.firstName} onChange={e => { setForm({ ...form, firstName: e.target.value }); }} /> </label> <label> Soyad: <input value={form.lastName} onChange={e => { setForm({ ...form, lastName: e.target.value }); }} /> </label> <label> E-posta: <input value={form.email} onChange={e => { setForm({ ...form, email: e.target.value }); }} /> </label> <p> {form.firstName}{' '} {form.lastName}{' '} ({form.email}) </p> </> ); }
Başlangıç state’ini yeniden yaratmaktan kaçınma
React başlangıç state’ini bir defa kaydeder ve sonraki render’larda görmezden gelir.
function TodoList() {
const [todos, setTodos] = useState(createInitialTodos());
// ...
createInitialTodos()
fonksiyonunun sonucu sadece başlangıç render’ında kullanılmasına rağmen, bu fonksiyonu hala her render’da yeniden çağırmaktasınız. Eğer bu fonksiyon büyük diziler ya da pahalı hesaplamalar yapıyorsa, bu israfa neden olabilir.
Bu durumu çözmek için bu fonksiyonu, useState
’e başlatıcı fonksiyon olarak iletebilirsiniz:
function TodoList() {
const [todos, setTodos] = useState(createInitialTodos);
// ...
Burada createInitialTodos
olarak ilettiğinize dikkat edin. Yani burada createInitialTodos()
fonksiyonunu çağırmanın sonucunu değil fonksiyonun kendisini iletiyoruz. Eğer useState
’e fonksiyon iletirseniz, React bu fonksiyonu sadece başlangıçta çağıracaktır.
React, geliştirme sırasında başlatıcıların saf olduğunu doğrulamak için onları iki defa çağırabilir.
Örnek 1 / 2: Başlatıcı fonksiyon iletme
Bu örnekte başlatıcı fonksiyon iletilmektedir yani createInitialTodos
fonksiyonu yalnızca başlangıçta çalışır. Input’a yazdığınızda olduğu gibi, bileşen yeniden render edildiğinde tekrar çalışmazlar.
import { useState } from 'react'; function createInitialTodos() { const initialTodos = []; for (let i = 0; i < 50; i++) { initialTodos.push({ id: i, text: 'Item ' + (i + 1) }); } return initialTodos; } export default function TodoList() { const [todos, setTodos] = useState(createInitialTodos); const [text, setText] = useState(''); return ( <> <input value={text} onChange={e => setText(e.target.value)} /> <button onClick={() => { setText(''); setTodos([{ id: todos.length, text: text }, ...todos]); }}>Ekle</button> <ul> {todos.map(item => ( <li key={item.id}> {item.text} </li> ))} </ul> </> ); }
State’i anahtar ile sıfırlama
Listeleri render ederken sık sık key
(anahtar
) niteliğini göreceksiniz. Ancak, bu başka bir amaca da hizmet etmektedir.
Bir bileşene farklı bir key
ileterek onun state’ini sıfırlayabilirsiniz. Bu örnekte Sıfırla butonu, Form
’a key
olarak ilettiğimiz version
state değişkenini değiştirir. key
değiştiğinde React, Form
bileşenini sıfırdan yeniden yaratır (ve tüm alt elemanlarını) böylelikle state sıfırlanmış olur.
Daha fazla bilgi edinmek için state’i korumak ve sıfırlamak sayfasını inceleyin.
import { useState } from 'react'; export default function App() { const [version, setVersion] = useState(0); function handleReset() { setVersion(version + 1); } return ( <> <button onClick={handleReset}>Sıfırla</button> <Form key={version} /> </> ); } function Form() { const [name, setName] = useState('Taylor'); return ( <> <input value={name} onChange={e => setName(e.target.value)} /> <p>Selam, {name}.</p> </> ); }
Önceki render’lardaki bilgiyi saklama
State’i genellikle olay yöneticileri içinde güncellersiniz. Ancak, bazı nadir durumlarda state’i render’a cevap olarak ayarlamak isteyebilirsiniz — örneğin, bir prop değiştiğinde state değişkenini değiştirmek isteyebilirsiniz.
Çoğu durumda buna ihtiyacınız yoktur:
- Eğer ihtiyacınız olan değer tamamen mevcut prop’lar ya da diğer state’ler kullanılarak hesaplanabiliyorsa, gereksiz state’i tamamen kaldırın. Sık sık yeniden hesaplama yapmaktan endişeliyseniz,
useMemo
Hook’u size yardımcı olabilir. - Tüm bileşen ağacının state’ini sıfırlamak istiyorsanız, bileşeninize farklı bir
key
iletin. - Eğer mümkünse, kullandığınız tüm state’leri olay yöneticileri ile güncelleyin.
Bunların hiçbirine uymayan nadir bir durum varsa, bileşeniniz render edilirken set
fonksiyonunu çağırarak şu ana kadar render edilmiş değerlere dayalı olarak state’i güncellemek için kullanabileceğiniz bir model vardır.
Aşağıdaki bunu gösteren bir örnektir. CountLabel
bileşeni kendisine iletilen count
prop’unu render etmektedir:
export default function CountLabel({ count }) {
return <h1>{count}</h1>
}
Diyelim ki sayacın son değişiklikten beri arttığını ya da azaldığını göstermek istiyorsunuz. count
prop’u size bunu söylemez — prop’un bir önceki değeri hakkında bilgiyi siz takip etmelisiniz. prevCount
state bileşenini önceki değerleri takip etmek için ekleyin. Sayacın arttığınımı yoksa azaldığınımı takip etmek için yeni bir trend
state değişkeni ekleyin. prevCount
ve count
değerlerini kıyaslayın ve değeler eşit değilse,prevCount
ve trend
değerlerini güncelleyin. Şimdi mevcut sayaç prop’unu ve son render’dan itibaren nasıl değiştiğini gösterebilirsiniz.
import { useState } from 'react'; export default function CountLabel({ count }) { const [prevCount, setPrevCount] = useState(count); const [trend, setTrend] = useState(null); if (prevCount !== count) { setPrevCount(count); setTrend(count > prevCount ? 'artıyor' : 'azalıyor'); } return ( <> <h1>{count}</h1> {trend && <p>Sayaç {trend}</p>} </> ); }
Şunu unutmayın ki eğer set
fonksiyonunu render esnasında çağırırsanız, bu fonksiyon prevCount !== count
gibi bir koşullu ifadenin içinde olmak zorundadır ve koşullu ifadenin içinde setPrevCount(count)
gibi bir çağrı olmak zorundadır. Aksi halde, bileşeniniz sonsuz bir döngü içinde çökene kadar yeniden render edilecektir. Aynı zamanda, şu anda render edilen bileşenin state’ini sadece bu şekilde güncelleyebilirsiniz. Başka bir bileşenin set
fonksiyonunu render esnasında çağırmak bir hatadır. Son olarak, set
fonksiyonu çağrınızın state’i mutasyona uğratmadan güncellemesine dikkat etmelisiniz — bu, sizin diğer saf fonksiyon kurallarını çiğneyebileceğiniz anlamına gelmez.
Bu modeli anlaması zor olabilir ve genel olarak bu modelden kaçınılması en yararlısıdır. Ancak, state’i Efekt içinde güncellemekten daha iyidir. set
fonksiyonunu render esnasında çağırdığınızda React, bileşeniniz bir return
ifadesine sahip olduktan hemen sonra ve alt elemanları render etmeden önce bu bileşeni yeniden render edecektir. Böylelikle, alt elemanların iki defa render edilmesine gerek olmayacaktır. Bileşeninizin geri kalan fonksiyonu hala çalışacaktır (ve sonuç görmezden gelinecektir). Eğer koşullu ifadeniz tüm Hook çağrılarının altındaysa, erken bir return;
ifadesi ekleyerek render etmeyi erken sıfırlayabilirsiniz.
Sorun giderme
State’i güncelledim ama konsolda eski değeri görüyorum
set
fonksiyonunu çağırmak çalışan koddaki state’i değiştirmez:
function handleClick() {
console.log(count); // 0
setCount(count + 1); // 1 ile yeniden render iste
console.log(count); // Hala 0!
setTimeout(() => {
console.log(count); // Bu da 0!
}, 5000);
}
Bunun nedeni state’in anlık görüntü olarak davranmasıdır. State’i güncellemek yeni state değeri ile başka bir render isteği gönderir ama bu halihazırda çalışan olay yöneticileri içindeki JavaScript count
değişkenini etkilemez.
Eğer bir sonraki state’i kullanmak istiyorsanız, değeri set
fonksiyonuna iletmeden önce başka bir değişkende saklayabilirsiniz:
const nextCount = count + 1;
setCount(nextCount);
console.log(count); // 0
console.log(nextCount); // 1
State’i güncelledim ama ekran güncellenmiyor
React, eğer bir sonraki state’iniz bir önceki ile eşitse güncellemeyi görmezden gelecektir. Bu karşılaştırma Object.is
ile yapılır. Bu durum genellikle state içindeki nesne ya da diziyi direkt olarak değiştirdiğiniz zaman meydana gelir:
obj.x = 10; // 🚩 Yanlış: nesneyi mutasyona uğratır
setObj(obj); // 🚩 Hiçbir şey yapmaz
Var olan bir obj
nesnesini mutasyona uğrattınız ve setObj
fonksiyonuna geri ilettiniz ve bu yüzden React güncellemeyi görmezden geldi. Bunu düzeltmek için, her zaman state içindeki nesneleri ve dizileri mutasyona uğratmak yerine değiştirdiğinizden emin olmalısınız:
// ✅ Doğru: yeni bir nesne yaratılır
setObj({
...obj,
x: 10
});
Bir hata alıyorum: “Çok fazla yeniden render”
Şunu söyleyen bir hata alabilirsiniz: Çok fazla yeniden render. React, sonsuz döngülerin önüne geçmek için yapılan render'ların sayısını kısıtlar.
Genel olarak bu, state’i render etme esnasında koşulsuz olarak değiştirdiğiniz anlamına gelir, yani bileşeniniz bir döngüye girer: render et, state’i değiştir (ki bu da bir render’a neden olur), render et, state’i değiştir (ki bu da bir render’a neden olur) ve bu böyle gider. Bu çoğunlukla olay yöneticisi içindeki bir hatadan kaynaklanmaktadır:
// 🚩 Yanlış: yöneticiyi render esnasında çağırır
return <button onClick={handleClick()}>Bana tıkla</button>
// ✅ Doğru: olay yöneticisini iletir
return <button onClick={handleClick}>Bana tıkla</button>
// ✅ Doğru: satır içi fonksiyon iletir
return <button onClick={(e) => handleClick(e)}>Bana tıkla</button>
Eğer hatanın nedenini bulamıyorsanız, konsolda hatanın yanındaki ok tuşuna basın ve hataya neden olan set
fonksiyonu çağrısını JavaScript içinde bulun.
Başlatıcım veya güncelleyici fonksiyonum iki defa çalışıyor
Strict Modda React, bazı fonksiyonlarınızı bir yerine iki defa çağıracaktır:
function TodoList() {
// Bu bileşen fonksiyonu her render'da iki defa çalışacaktır.
const [todos, setTodos] = useState(() => {
// Bu başlatıcı fonksiyon başlangıç sırasında iki defa çalışacaktır.
return createTodos();
});
function handleClick() {
setTodos(prevTodos => {
// Bu güncelleyici fonksiyonu her bir tıklama için iki defa çalışacaktır.
return [...prevTodos, createTodo()];
});
}
// ...
Bu beklendik bir durumdur ve kodunuzda bir soruna neden olmamalıdır.
Bu sadece geliştirme sırasında olan davranış bileşenlerinizi saf tutmanıza yardımcı olur. React, yapılan çağrılardan birinin sonucunu kullanır ve diğer çağrının sonucunu görmezden gelir. Bileşeniniz, başlatıcınız ve güncelleyici fonksiyonunuz saf olduğu sürece bu durum mantığınızı etkilememelidir. Ancak bu davranış, saf olmayan fonksiyonlarınız varsa, yaptığız hataları bulmanıza yardımcı olur.
Örneğin, bu saf olmayan güncelleyici fonksiyonu state içindeki diziyi mutasyona uğratmaktadır:
setTodos(prevTodos => {
// 🚩 Yanlış: state'i mutasyona uğratır
prevTodos.push(createTodo());
});
React güncelleme fonksiyonlarını iki defa çağırdığından dolayı, yapılacak işin iki kere eklendiğini göreceksiniz. Yani burada bir hata olduğunu bileceksiniz. Bu örnekteki hatayı, diziyi mutasyona uğratmak yerine değiştirerek çözebilirsiniz:
setTodos(prevTodos => {
// ✅ Doğru: yeni state ile değiştirilir
return [...prevTodos, createTodo()];
});
Şimdi güncelleme fonksiyonu saf olduğuna göre, fonksiyonu iki defa çağırmak davranışta herhangi bir farklılığa yol açmayacaktır. Bu yüzden React’in fonksiyonu iki defa çağırması hataları bulmanıza yardımcı olur. Sadece bileşen, başlatıcı ve güncelleyici fonksiyonlar saf olmalıdır. Olay yöneticilerinin saf olmasına gerek yoktur yani React olay yöneticilerinizi asla iki defa çağırmayacaktır.
Daha fazla bilgi edinmek için bileşenleri saf tutmak sayfasını okuyabilirsiniz.
State’e bir fonksiyon koymak istiyorum ama fonksiyon çağrılıyor
State içine bir fonksiyonu böyle koyamazsınız:
const [fn, setFn] = useState(someFunction);
function handleClick() {
setFn(someOtherFunction);
}
Bir fonksiyon ilettiğinizden dolayı React, someFunction
fonksiyonunun başlatıcı fonksiyon olduğunu düşünecektir ve someOtherFunction
fonksiyonu bir güncelleyi fonksiyondur, bu yüzden React bu fonksiyonu çağırmaya ve sonucunu saklamaya çalışacaktır. Bir fonksiyonu saklamanın asıl yolu, () =>
ifadesini her iki durumda da fonksiyondan önceye eklemektir. Böylelikle React, ilettiğiniz fonksiyonları saklayacaktır.
const [fn, setFn] = useState(() => someFunction);
function handleClick() {
setFn(() => someOtherFunction);
}