# React 19 useEffectEvent ve Activity: Yeni API'ler ve 2026 Mulakat Sorulari > React 19.2 useEffectEvent ve Activity API detayli incelemesi. Stale closure cozumleri, arka plan on-render, kod ornekleri ve 2026 mulakat sorulari. - Published: 2026-06-03 - Updated: 2026-06-03 - Author: SharpSkill - Tags: react, useEffectEvent, activity, react 19, hooks, interview - Reading time: 11 min --- React 19.2, uzun süredir deneysel aşamada olan iki önemli API'yi kararlı sürüme taşıdı: `useEffectEvent` ve `Activity`. Bu iki API, React uygulamalarında sıkça karşılaşılan iki temel soruna çözüm sunuyor. `useEffectEvent`, effect içindeki stale closure problemini ortadan kaldırırken, `Activity` bileşeni arka planda ön-render işlemleri gerçekleştirerek kullanıcı deneyimini iyileştiriyor. Bu makale, her iki API'nin çalışma prensiplerini, kullanım kurallarını, yaygın tuzaklarını ve teknik mülakatlarda karşılaşılabilecek soruları kapsamlı şekilde ele almaktadır. > **React 19.2 Gereksinimi** > > `useEffectEvent` ve `Activity` API'leri yalnızca [React 19.2 ve sonraki sürümlerde](https://react.dev/blog/2025/10/01/react-19-2) kararlı olarak kullanılabilir. Proje bağımlılıklarının en az `react@19.2.0` sürümüne güncellendiğinden emin olunmalıdır. ## Stale Closure Problemi ve useEffectEvent Çözümü React geliştiricilerinin en sık karşılaştığı sorunlardan biri, `useEffect` içindeki callback fonksiyonlarının eski (stale) değerlere referans vermesidir. Bu durum, bir effect'in bağımlılık dizisinde yer almayan ancak callback içinde kullanılan değişkenlerin güncel halini okuyamamasından kaynaklanır. Geleneksel çözüm, `useRef` kullanarak değeri manuel olarak güncel tutmaktı; ancak bu yaklaşım hem okunabilirliği azaltır hem de linter uyarılarına neden olur. Aşağıdaki örnekte, bir sohbet odası bağlantısı yönetilirken `theme` değerinin güncel kalması için `useRef` ile geçici bir çözüm uygulanmıştır: ```tsx // hooks/useChatRoom.ts // Before useEffectEvent: useRef workaround import { useEffect, useRef } from 'react' export function useChatRoom(roomId: string, theme: string) { // Store theme in a ref to avoid stale closure const themeRef = useRef(theme) themeRef.current = theme useEffect(() => { const connection = createConnection(roomId) connection.on('message', (msg) => { // themeRef.current always has the latest value logAnalytics('new_message', { roomId, theme: themeRef.current }) showNotification(msg) }) connection.connect() return () => connection.disconnect() }, [roomId]) // theme intentionally excluded — but linter warns } ``` Bu kod çalışıyor olsa da, birkaç ciddi dezavantajı bulunmaktadır. İlk olarak, `theme` bağımlılık dizisinden kasıtlı olarak çıkarıldığı için ESLint `exhaustive-deps` kuralı uyarı verir. İkinci olarak, `useRef` ile yapılan bu geçici çözüm, kodun asıl amacını gizler ve bakım maliyetini artırır. Üçüncü olarak, ekip üyelerinin bu pattern'i anlaması ve doğru uygulaması gerekir, bu da hata riskini yükseltir. `useEffectEvent` hook'u bu sorunu kökünden çözer. Bir Effect Event olarak tanımlanan fonksiyon, her zaman en güncel prop ve state değerlerini okur, ancak effect'in yeniden çalışmasını tetiklemez: ```tsx // hooks/useChatRoom.ts // After useEffectEvent: clean separation of concerns import { useEffect, useEffectEvent } from 'react' export function useChatRoom(roomId: string, theme: string) { // Effect Event: always reads latest theme, never triggers reconnect const onMessage = useEffectEvent((msg: string) => { logAnalytics('new_message', { roomId, theme }) showNotification(msg) }) useEffect(() => { const connection = createConnection(roomId) connection.on('message', onMessage) connection.connect() return () => connection.disconnect() }, [roomId]) // No linter warning — onMessage is an Effect Event } ``` Bu yaklaşımda `theme` değişkeni doğrudan `useEffectEvent` callback'i içinde okunmaktadır. React, bu fonksiyonun bir Effect Event olduğunu bildiği için, `theme` değişimlerinde effect'i yeniden çalıştırmaz ancak callback çağrıldığında her zaman güncel `theme` değerini kullanır. Linter uyarısı da ortadan kalkar, çünkü `onMessage` bir Effect Event olarak tanınır ve bağımlılık dizisine eklenmesi gerekmez. ## useEffectEvent Kuralları ve Kısıtlamaları `useEffectEvent` son derece güçlü bir araç olsa da, belirli kurallar dahilinde kullanılmalıdır. Bu kurallar, API'nin doğru çalışmasını garanti altına alır ve olası hataların önüne geçer. **Kural 1: Yalnızca useEffect içinden çağrılmalıdır.** Bir Effect Event, doğrudan event handler olarak veya render sırasında çağrılamaz. Yalnızca bir `useEffect` bloğunun içinden tetiklenmelidir. **Kural 2: Asla başka bileşenlere veya hook'lara aktarılmamalıdır.** Effect Event fonksiyonları, tanımlandıkları bileşenin kapsamında kalmalıdır. Props olarak alt bileşenlere geçirilmesi veya başka hook'lara parametre olarak verilmesi desteklenmez. **Kural 3: Bağımlılık dizisine dahil edilmez.** React, `useEffectEvent` ile oluşturulan fonksiyonları özel olarak işler ve bunların bağımlılık dizisine eklenmesini gerektirmez. Aşağıdaki örnek, bu kuralların doğru uygulandığı bir arama izleme bileşenini göstermektedir: ```tsx // components/SearchTracker.tsx // Correct: Effect Event used inside useEffect import { useEffect, useEffectEvent, useState } from 'react' interface SearchTrackerProps { query: string userId: string } export function SearchTracker({ query, userId }: SearchTrackerProps) { const [results, setResults] = useState([]) // Track searches with current user context const onSearchComplete = useEffectEvent((resultCount: number) => { analytics.track('search_complete', { query, userId, // Always latest userId resultCount, timestamp: Date.now(), }) }) useEffect(() => { const controller = new AbortController() fetchSearchResults(query, controller.signal).then((data) => { setResults(data) onSearchComplete(data.length) // Called from inside useEffect }) return () => controller.abort() }, [query]) // userId excluded safely — lives in the Effect Event return } ``` Bu örnekte `userId` değişkeni bağımlılık dizisinden güvenle çıkarılmıştır. Kullanıcı kimliği değiştiğinde arama yeniden tetiklenmez, ancak analitik izleme her zaman güncel `userId` değerini kullanır. Bu, reaktif davranış (arama sorgusuna tepki verme) ile reaktif olmayan davranış (güncel bağlamı okuma) arasındaki ayrımı net bir şekilde ortaya koyar. > **Yaygın Hata: Render Sırasında Çağırma** > > `useEffectEvent` ile oluşturulan fonksiyonların render sırasında veya JSX içinden doğrudan çağrılması çalışma zamanı hatasına neden olur. Bu fonksiyonlar yalnızca `useEffect` callback'i içinden çağrılmalıdır. `onClick` gibi DOM event handler'larında kullanılması gereken durumlarda, standart bir fonksiyon tanımı tercih edilmelidir. ## Activity Bileşeni: Arka Planda Ön-Render `Activity`, React 19.2 ile birlikte gelen ve bileşenlerin arka planda ön-render edilmesini sağlayan yeni bir yerleşik bileşendir. Daha önce `` adıyla deneysel olarak geliştirilen bu API, artık kararlı sürümde `Activity` adıyla kullanılmaktadır. Temel amacı, kullanıcının henüz görmediği ancak kısa süre içinde görme ihtimali yüksek olan içerikleri önceden hazırlamaktır. `Activity` bileşeni, `mode` prop'u aracılığıyla iki farklı modda çalışır: `'visible'` ve `'hidden'`. `visible` modunda bileşen normal şekilde render edilir ve kullanıcıya gösterilir. `hidden` modunda ise bileşen DOM'a düşük öncelikle render edilir, ancak kullanıcıya gösterilmez. Önemli olan nokta, `hidden` modundaki bileşenlerin state'inin korunmasıdır. Bu sayede bir bileşen `hidden`'dan `visible`'a geçtiğinde, tüm form verileri, scroll pozisyonu ve yerel state aynen kaldığı yerden devam eder. Aşağıdaki örnek, sekme geçişlerinde form durumunun korunmasını sağlayan bir tab layout bileşenini göstermektedir: ```tsx // components/TabLayout.tsx // Activity preserves form state across tab switches import { useState } from 'react' import { Activity } from 'react' interface Tab { id: string label: string content: React.ReactNode } export function TabLayout({ tabs }: { tabs: Tab[] }) { const [activeTab, setActiveTab] = useState(tabs[0].id) return (
{tabs.map((tab) => ( {tab.content} ))}
) } ``` Bu yaklaşımda her sekme her zaman render edilmektedir, ancak yalnızca aktif sekme kullanıcıya gösterilir. Geleneksel koşullu render yaklaşımında (`{activeTab === tab.id && tab.content}`) sekme değiştirildiğinde bileşen unmount olur ve tüm yerel state kaybolur. `Activity` ile bu sorun tamamen ortadan kalkar. ## Ön-Render ile Rota Hazırlama `Activity` bileşeninin en güçlü kullanım alanlarından biri, kullanıcının bir sonraki adımda ziyaret etme olasılığı yüksek olan rotaları arka planda hazırlamaktır. Bu teknik, algılanan yükleme süresini önemli ölçüde azaltır: ```tsx // components/PrerenderedRoute.tsx // Pre-render the next likely route in the background import { Activity, Suspense, use } from 'react' interface PrerenderedRouteProps { isActive: boolean dataPromise: Promise } export function PrerenderedRoute({ isActive, dataPromise }: PrerenderedRouteProps) { return ( }> ) } function DashboardContent({ dataPromise }: { dataPromise: Promise }) { // use() reads the cached promise — works during hidden pre-render const data = use(dataPromise) return (
) } ``` Bu örnekte `use()` hook'u, promise'i okuyarak veriyi çözer. `hidden` modunda bu işlem arka planda gerçekleşir ve kullanıcı ilgili rotaya geçtiğinde içerik anında görüntülenir. `Suspense` ile birlikte kullanıldığında, veri henüz hazır değilken iskelet (skeleton) bileşeni gösterilir ve veri geldiğinde otomatik olarak asıl içerik ile değiştirilir. ## Activity ve TanStack Query Tuzağı `Activity` bileşeni ile TanStack Query birlikte kullanıldığında dikkat edilmesi gereken kritik bir davranış bulunmaktadır. `hidden` modundaki bir `Activity` içindeki `useQuery` hook'ları veri çekme işlemini gerçekleştirmez. Bu, React'in `hidden` bileşenlerdeki effect'leri geciktirmesinden kaynaklanır ve beklenmedik boş state durumlarına yol açabilir. ```tsx // components/UserDashboard.tsx // Problem: useQuery won't fetch when Activity is hidden import { useQuery, useQueryClient } from '@tanstack/react-query' import { Activity } from 'react' function UserStats() { // This useQuery will NOT run while hidden const { data } = useQuery({ queryKey: ['user-stats'], queryFn: fetchUserStats, }) return } // Solution: prefetch data outside the Activity boundary function DashboardWithPrefetch({ showStats }: { showStats: boolean }) { const queryClient = useQueryClient() // Prefetch at the parent level — runs regardless of Activity mode queryClient.ensureQueryData({ queryKey: ['user-stats'], queryFn: fetchUserStats, }) return ( ) } ``` Çözüm, veri çekme işlemini `Activity` sınırının dışına taşımaktır. `queryClient.ensureQueryData()` yöntemi, üst bileşen seviyesinde çağrılarak `Activity` modundan bağımsız şekilde çalışır. Böylece bileşen `visible` moduna geçtiğinde, TanStack Query önbelleğinde zaten mevcut olan veriyi anında okur. Bu pattern, [TanStack Query ile ilgili detaylı bilgiler](/technologies/react-next/interview-questions/react-query-tanstack) için referans kaynağında incelenebilir. > **Genel Kural: Effect'ler ve hidden Mod** > > `Activity` bileşeni `hidden` modundayken yalnızca render işlemi gerçekleşir; `useEffect`, `useLayoutEffect` ve bunlara bağlı abonelikler (TanStack Query dahil) çalışmaz. Bu davranış, arka plan render'ının yan etki üretmemesi ilkesine dayanır. Veri çekme işlemleri her zaman `Activity` sınırının dışında başlatılmalıdır. ## useEffectEvent ve Activity Birlikte Kullanımı Bu iki API'nin birlikte kullanıldığı senaryolar, özellikle gerçek zamanlı uygulamalarda güçlü bir mimari sunar. Aşağıdaki örnekte, çok kanallı bir canlı yayın paneli hem WebSocket bağlantı yönetimini hem de sekme geçişlerini sorunsuz şekilde gerçekleştirmektedir: ```tsx // components/LiveDashboard.tsx import { useEffect, useEffectEvent, useState } from 'react' import { Activity } from 'react' function LiveFeed({ channel, userId }: { channel: string; userId: string }) { const [messages, setMessages] = useState([]) // Analytics tracking with latest userId — no effect re-sync const onNewMessage = useEffectEvent((msg: Message) => { analytics.track('live_message', { channel, userId }) setMessages((prev) => [...prev, msg]) }) useEffect(() => { const ws = new WebSocket(`wss://api.example.com/${channel}`) ws.onmessage = (event) => { const msg = JSON.parse(event.data) as Message onNewMessage(msg) } return () => ws.close() }, [channel]) // Clean reconnect only when channel changes return } export function LiveDashboard({ userId }: { userId: string }) { const [activeChannel, setActiveChannel] = useState('general') const channels = ['general', 'alerts', 'metrics'] return (
{channels.map((ch) => ( ))}
) } ``` Bu mimaride `useEffectEvent`, `userId` değiştiğinde WebSocket bağlantısının yeniden kurulmasını engellerken, `Activity` bileşeni kanal geçişlerinde mesaj geçmişinin kaybolmasını önler. Kullanıcı bir kanaldan diğerine geçip geri döndüğünde, tüm mesajlar yerinde kalır. `hidden` moddaki kanalların effect'leri çalışmadığından, gereksiz WebSocket bağlantıları da oluşmaz. Bu durum, performans ve kaynak yönetimi açısından önemli bir avantaj sağlar. ## Teknik Mülakat Soruları Bu bölümde, [React Hooks mülakat soruları](/technologies/react-next/interview-questions/react-hooks) kapsamında `useEffectEvent` ve `Activity` API'leri ile ilgili sıkça sorulan soruları ve beklenen yanıtları ele alınmaktadır. **Soru 1: useEffectEvent, useCallback'ten ne açıdan farklıdır?** `useCallback`, memoize edilmiş bir fonksiyon döndürür ve bağımlılık dizisi değiştiğinde fonksiyonu yeniden oluşturur. Effect'in bağımlılık dizisine dahil edilmesi gerekir ve dahil edildiğinde effect'in yeniden çalışmasını tetikleyebilir. `useEffectEvent` ise her zaman güncel prop ve state değerlerini okuyan, ancak effect'in bağımlılık dizisine dahil edilmeyen ve effect'in yeniden çalışmasını asla tetiklemeyen bir fonksiyon döndürür. **Soru 2: Bir useEffectEvent fonksiyonu doğrudan bir onClick handler olarak kullanılabilir mi?** Hayır, kullanılamaz. `useEffectEvent` ile oluşturulan fonksiyonlar yalnızca `useEffect` içinden çağrılabilir. DOM event handler'larında doğrudan kullanım desteklenmez ve çalışma zamanı hatasına neden olur. Bu kuralın amacı, reaktif ve reaktif olmayan kod arasındaki sınırı netleştirmektir. **Soru 3: Activity bileşeni hidden modundayken useEffect çalışır mı?** Hayır, çalışmaz. `hidden` modunda React yalnızca bileşeni render eder, ancak effect'leri, layout effect'lerini ve bunlara bağlı abonelikleri çalıştırmaz. Effect'ler yalnızca bileşen `visible` moduna geçtiğinde tetiklenir. Bu davranış, arka plan render'ının yan etki üretmemesini garanti eder. **Soru 4: Activity ile koşullu render arasındaki temel fark nedir?** Koşullu render (`{condition && }`) bileşeni tamamen unmount eder ve yeniden mount ettiğinde tüm yerel state sıfırlanır. `Activity` ise bileşeni DOM'da tutarak state'ini korur. Form verileri, scroll pozisyonu ve bileşen içi değişkenler, mod geçişlerinde aynen kalır. **Soru 5: TanStack Query, hidden bir Activity içinde neden veri çekmez ve bu nasıl çözülür?** TanStack Query, `useQuery` hook'unun effect'lerine bağlıdır. `hidden` modunda effect'ler çalışmadığından, veri çekme işlemi başlatılmaz. Çözüm olarak `queryClient.ensureQueryData()` veya `queryClient.prefetchQuery()` yöntemleri `Activity` sınırının dışında çağrılmalıdır. Böylece veri, bileşenin mod durumundan bağımsız olarak hazır hale gelir. **Soru 6: useEffectEvent ve Activity birlikte kullanıldığında WebSocket bağlantı yönetimi nasıl etkilenir?** `Activity` bileşeni `hidden` modundayken effect'ler çalışmaz, dolayısıyla yeni WebSocket bağlantıları oluşturulmaz. Bileşen `visible` moduna geçtiğinde effect çalışır ve bağlantı kurulur. `useEffectEvent` sayesinde bağlantı callback'i her zaman güncel değerleri okur, ancak bağlantının kendisi yalnızca asıl bağımlılıklar (örneğin kanal adı) değiştiğinde yeniden kurulur. Bu kombinasyon, gereksiz bağlantı ve yeniden bağlantı maliyetini ortadan kaldırır. ## Sonuc `useEffectEvent` ve `Activity`, React 19.2 ile birlikte gelen ve farklı ancak birbirini tamamlayan sorunları çözen iki temel API'dir. `useEffectEvent`, stale closure sorununu temiz bir şekilde ortadan kaldırarak effect'lerdeki reaktif ve reaktif olmayan mantığın ayrılmasını sağlar. `Activity` ise bileşen state'ini koruyarak ve arka planda ön-render yaparak kullanıcı deneyimini önemli ölçüde iyileştirir. Her iki API'nin kurallarını ve kısıtlamalarını anlamak, hem üretim kodunda hatasız kullanım hem de teknik mülakatlarda başarılı performans için kritik öneme sahiptir. Detaylı bilgi için [React 19.2 resmi duyurusu](https://react.dev/blog/2025/10/01/react-19-2) ve [useEffectEvent referans dokümantasyonu](https://react.dev/reference/react/useEffectEvent) incelenebilir. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/react-next/react-19-useeffectevent-activity-new-apis-interview-questions