Mehmet

WFN Üye
Konular
1,851
Mesajlar
1,852
Çözüm
0
Ticaret Puanı
0
Üyelik
1 Ay 6 Gün
Konum
YurtDışı
Web Sitesi
Var
Alanı
Google Adsense
1/1
Konu sahibi
React’te state setter’ı çağrıldığında mevcut fonksiyon çalışmasının içindeki değişken anında değişmez. Setter sonraki render için güncelleme ister. Çalışmakta olan handler ve onun oluşturduğu callback, ait olduğu render’ın state görüntüsünü korur; daha sonra yeni render tamamlanması eski closure içindeki değişkeni değiştirmez. Bu nedenle setter’dan hemen sonra yapılan console.log, aynı olay işleyicisindeki başka bir işlem veya eski bir zamanlayıcı callback’i önceki değeri okuyabilir.

State neden aynı fonksiyon içinde değişmez?​


Her render, state değerlerinin o render’a ait bir kopyasıyla çalışır. Aşağıdaki bileşende setter çağrılır; ancak ilk tıklamada hemen sonraki log 0 yazar:

Kod:
import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
    console.log("Bu render içindeki değer:", count);
  }

  return (
    <button type="button" onClick={handleClick}>
      {count} artır
    </button>
  );
}

Beklenen davranış şudur: İlk tıklamada log eski render’dan gelen 0 değerini yazar, ardından React yeni render’ı yapar ve ekranda 1 görünür. Bu, setter’ın çalışmadığı anlamına gelmez; log, yeni render’dan önce çalışmıştır.

Yeni değeri kullanarak hesap yapmak istiyorsanız değeri önce normal bir değişkende hesaplayın:

Kod:
function handleClick() {
  const nextCount = count + 1;
  setCount(nextCount);
  console.log("Planlanan yeni değer:", nextCount);
}

Yeni değerin önceki state’e bağlı olduğu durumlarda fonksiyonel güncelleme kullanın. Özellikle aynı olay içinde birden fazla güncelleme yapılıyorsa bu yaklaşım güvenlidir:

Kod:
function handleClick() {
  setCount(previousCount => previousCount + 1);
  setCount(previousCount => previousCount + 1);
}

Bu örnekte amaç iki artırmaysa, setCount(count + 1) ifadesini iki kez yazmak güvenilir değildir; iki çağrı da aynı eski count değerini temel alabilir. Fonksiyonel güncellemede React her işlemin önceki sonucu üzerinden devam eder.

Yeni değeri nerede okumalı?​


Değişen state ile dış bir sistemi senkronize edecekseniz, gerekli bağımlılıklarla useEffect kullanabilirsiniz. Yalnızca tıklama nedeniyle yapılacak bir iş için yeni değeri handler içinde hesaplamak genellikle yeterlidir; her işlem için effect eklemeyin. Aşağıdaki örnek yeni render’ın değerini loglamak içindir:

Kod:
import { useEffect, useState } from "react";

function SearchStatus() {
  const [query, setQuery] = useState("");

  useEffect(() => {
    console.log("Yeni query:", query);
  }, [query]);

  return (
    <label>Arama
      <input value={query} onChange={event => setQuery(event.target.value)} />
    </label>
  );
}

Effect içindeki query, ilgili render’ın güncel değeridir. Ancak effect’e eksik bağımlılık yazmak eski değerin kullanılmasına yol açabilir. Effect içinde okunan reactive değerleri bağımlılık listesine ekleyin; yalnızca bilinçli olarak sabit kalan değerleri dışarıda bırakın.

Karar vermeyi kolaylaştırmak için okuma amacınızı şu şekilde ayırabilirsiniz:

İhtiyaçUygun yaklaşımKaçınılacak yaklaşım
Yeni state’i hemen hesaplamakÖnce nextValue değişkeni oluşturmakSetter’dan sonra state değişkenini okumak
Önceki state’e göre güncellemekFonksiyonel setter kullanmakEski kapanımdaki değeri tekrar kullanmak
Güncelleme sonrasındaki yan etkiDoğru bağımlılıklarla useEffectYan etkiyi setter’ın hemen sonrasına koymak
Render’lar arasında güncel, ekrana yansımayan değerGerekiyorsa useRefRef değişimini state render’ı sanmak

Eski closure ve zamanlayıcılar​


setTimeout, event callback’i veya abonelik içinde kullanılan state, callback oluşturulduğu render’ın değerini taşıyabilir. Böyle bir callback’in her güncel değeri görmesi gerekiyorsa effect bağımlılıklarını ve aboneliğin yaşam döngüsünü düzeltin. Güncel değeri render tetiklemeden saklamak gerçekten gerekiyorsa useRef kullanılabilir:

Kod:
import { useEffect, useRef, useState } from "react";

export default function TimerCounter() {
  const [count, setCount] = useState(0);
  const latestCount = useRef(count);

  useEffect(() => {
    latestCount.current = count;
  }, [count]);

  function handleTimer() {
    setTimeout(() => console.log(latestCount.current), 1000);
  }

  return <>
    <button type="button" onClick={() => setCount(c => c + 1)}>{count} artır</button>
    <button type="button" onClick={handleTimer}>Bir saniye sonra oku</button>
  </>;
}

Bu örnekte ref, effect tamamlandığında son commit edilen state ile eşitlenir; render sırasında ref’e yazılmaz. Ref’in current değerini değiştirmek yeni render başlatmaz. Dolayısıyla ekranda gösterilecek bir değer için ref değil state kullanın.

Sık yapılan hatalar​


  • Setter’dan hemen sonra state değişkeninin yeni olduğunu varsaymak.
  • Önceki state’e bağlı işlemlerde doğrudan setState(value + 1) kullanmak.
  • Effect bağımlılık listesinden kullanılan state’i çıkarmak.
  • Güncel değeri göstermek için ref kullanıp ref değişince bileşenin kendiliğinden render olmasını beklemek.
  • Sorunu yalnızca React’in toplu güncellemesine bağlamak; asıl nedenin eski closure veya eksik effect bağımlılığı olup olmadığını kontrol etmemek.
Teşhis için önce log’u setter’dan sonraki satırdan kaldırıp yeni render’ı gözlemleyin. Değer render sonrasında da yanlışsa setter’a verilen değeri, fonksiyonel güncellemeyi ve ilgili effect bağımlılıklarını sırayla kontrol edin.

Kaynaklar​



Sık sorulan sorular​


State setter’ı çağırınca neden hemen return değeri gelmez?​


State setter bir değer döndürmez; React’e sonraki render için güncelleme bildirir. Sonucu aynı olayda kullanmanız gerekiyorsa yeni değeri kendiniz hesaplayın. Effect’i ancak dış sistemle senkronizasyon gerekiyorsa kullanın.

React state güncellemelerini neden bazen birleştirir?​


React, aynı render sürecinde yapılan güncellemeleri verimli biçimde gruplayabilir. Kodunuzun bu davranışın ayrıntılarına bağlı olmaması için önceki state’i temel alan güncellemelerde fonksiyonel setter kullanın.

State mi, ref mi kullanmalıyım?​


Değişiklik ekranda görünmeli ve render başlatmalıysa state kullanın. Değer render başlatmadan callback’ler arasında saklanacaksa ref uygun olabilir; ref’in değişmesi tek başına arayüzü güncellemez.
 

Sende şimdi bize katılmak ister misin?

Kayıt ol

Bize katılım kolay ve ücretsizdir!

Konuyu görüntüleyenler

Bu konuyu şu anda görüntüleyen üye bulunmuyor.
Robotlar:
  • Anthropic