Cansu Arı Logo
Blog
Nasıl Yapılır?

useTransition, useDeferredValue ve Zamanlama Yönetimi

React 18 ile gelen useTransition ve useDeferredValue hook’ları, kullanıcı etkileşimlerinde gecikmeyi minimize eder.

  • #React
  • #Performans

Skip to content

React Render zamanlamasını akıllıca yönetmenin yolu

React, kullanıcı etkileşimlerine verdiği tepki süresini kısaltmak için yeni bir dönem başlattı.
React 18 ile gelen Concurrent Rendering sistemi sayesinde artık render işlemleri önceliklendirilerek çalışıyor.
Ve bu dünyada iki yeni kahraman var: useTransition ve useDeferredValue.
Eğer Vue.js'e aşinaysanız nextTick, Suspense, flush: 'post', useDebounce, useThrottle, watchEffect ile custom çözümlerin default olarak zaten var olduğunu bilirsiniz ve aslında mantık aynı.

Bu yazıda, bu iki hook’un nasıl çalıştığını, farklarını ve pratik kullanım senaryolarını inceleyeceğiz.


Ön Bilgi: Concurrent Rendering Nedir?

React 18’den önce her render işlemi senkrondu. Yani kullanıcı yazarken bile React her değişiklikte UI’ı baştan oluşturuyordu. Şimdi React render işlemlerini öncelik sırasına koyabiliyor:
  • Acil (urgent) işler → buton tıklama, input yazma.
  • Geç (non-urgent) işler → filtreleme, liste güncelleme, grafik çizimi.
💡 Bu sistemin amacı: Kullanıcı etkileşimleri asla “donmasın.”

useTransition: Yoğun Render İşlerini Ertele

useTransition, uzun süren render işlemlerini “arka plana” alır. Yani React’a der ki: “Önce kullanıcıyı bekletme, bu işi sonra yap.”
const [isPending, startTransition] = useTransition()

function handleChange(e) {
const value = e.target.value
startTransition(() => {
setFilter(value)
})
}

Ne Oluyor Burada?

  • Kullanıcı inputa yazıyor.
  • React önce input değerini hemen güncelliyor (acil iş).
  • Liste filtreleme işlemi startTransition içine alındığı için daha sonra yapılır (non-urgent iş).
Sonuç: Input takılmadan yanıt verir, liste ise arka planda güncellenir. 🪄

isPending Ne İşe Yarar?

isPending true olduğunda, React geç işlerin devam ettiğini belirtir.
{isPending && <span>Filtreleniyor...</span>}
Bu sayede kullanıcıya yüklenme durumunu gösterebilirsin.

Özet: useTransition = "Render’ı geciktir, ama kullanıcı deneyimini koru."


Gerçek Hayat Örneği

function Search() {
const [query, setQuery] = useState('')
const [results, setResults] = useState([])
const [isPending, startTransition] = useTransition()

const handleChange = (e) => {
const value = e.target.value
setQuery(value)
startTransition(() => {
setResults(bigData.filter(item => item.includes(value)))
})
}

return (
<>
<input value={query} onChange={handleChange} placeholder="Ara..." />
{isPending && <p>Aranıyor...</p>}
<ul>
{results.map(r => <li key={r}>{r}</li>)}
</ul>
</>
)
}
Input anında güncellenir, ama filtreleme işi arkaya atılır. Sonuç: Donmayan, pürüzsüz bir arama deneyimi. ✅

useDeferredValue: Değeri Erteleyerek Güncelle

useDeferredValue, bir değeri “gecikmeli” hale getirir. Bu sayede o değere bağlı render işlemleri hemen değil, sistem uygun olduğunda çalışır.
const deferredQuery = useDeferredValue(query)
const filteredList = bigData.filter(item => item.includes(deferredQuery))
Burada query anında değişir, ama deferredQuery biraz sonra güncellenir. Yani kullanıcı inputu yazarken UI donar gibi olmaz.

useTransition vs useDeferredValue

ÖzellikuseTransitionuseDeferredValue
Ne yapar?Bir state güncellemesini ertelerBir değerin güncellenmesini erteler
Kullanım yeriState setter etrafındaDeğerin kendisinde
Kontrol kimde?Geliştiricide (startTransition)React’te
Kullanım amacıYoğun state değişimleriAğır hesaplama gerektiren değerler
💡 Kısaca: useTransition = işlemi ertele, useDeferredValue = değeri ertele.

Birlikte Kullanım Örneği

function FilterList({ items }) {
const [query, setQuery] = useState('')
const deferredQuery = useDeferredValue(query)
const [isPending, startTransition] = useTransition()

const filtered = items.filter(i => i.includes(deferredQuery))

return (
<>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Filtrele..."
/>
{isPending && <p>Güncelleniyor...</p>}
<ul>
{filtered.map(f => <li key={f}>{f}</li>)}
</ul>
</>
)
}
Burada:
  • query anında değişiyor.
  • deferredQuery biraz gecikmeli geliyor.
  • UI hiçbir zaman takılmıyor.

Neden Önemli?

React, her render’ı eşit öncelikte çalıştırırsa, kullanıcı deneyimi kötüleşir. Büyük bir proje düşün; tüm kodlar aynı anda çalışmaya çalışırsa sistem çökebilir veya çok yavaşlayabilir. React ise bu iki hook sayesinde artık şunu ayırt ediyor:
  • “Kullanıcının gördüğü şeyler acil.”
  • “Listeyi sonra da güncelleyebilirim.”
Yani artık UI “tepki veriyor gibi” değil, gerçekten tepkisel (responsive) çalışıyor.

Performans Tavsiyeleri

  1. Uzun süren hesaplamaları startTransition içine al.
  2. Kullanıcı etkileşimlerini (click, input) asla bloklama.
  3. Geri bildirim vermek için isPending durumunu göster.
  4. Gereksiz render’ları azaltmak için useMemo ve useCallback kullan.

useTransition + Suspense = Güçlü İkili

React 18 ile Suspense artık data fetching süreçlerinde useTransition ile birlikte çalışabiliyor.
startTransition(() => {
setResource(fetchData())
})
React, bu geçişi “low priority” olarak işaretliyor ve kullanıcıyı bekletmeden loading durumunu gösteriyor.

💡 Pro tip: Transition’lar artık “UI state machine” mantığıyla davranıyor -- bekleme, gösterme, güncelleme sırası otomatikleşti.


Gözle Görülmeyen Kazanç

Bir input’un 200ms geç tepki verdiğini fark etmeyebilirsin, ama kullanıcı fark eder. useTransition ve useDeferredValue, bu farkı görünmez hale getirir. Küçük hissedilen farklar, büyük deneyim kazancı yaratır.

Sonuç

React 18 ve sonrası, sadece "render eden" değil, önceliklendiren bir framework. Bu iki hook, modern arayüzlerde akıcılığı garanti altına alır.

Kısaca:

  • useTransition → Ağır state değişimlerini ertele.
  • useDeferredValue → Değeri geciktirerek performansı koru.
  • İkisini birlikte kullan → Donmayan, nefes alan bir UI yarat.

All tags
  • React
  • Performans