React 19 Stabil Yayınlandı: Actions, use Hook ve Yeni Paradigmalar

React 19 Stabil Yayınlandı: Actions, use Hook ve Yeni Paradigmalar

React'ın En Büyük Mimari Güncellemesi

React ekibi, 5 Aralık 2024'te React 19'u stabil olarak yayınladı. React 16.8'de Hook'ların tanıtılmasından bu yana en büyük mimari değişiklik olarak kabul edilen bu sürüm, form yönetimi, veri akışı ve sunucu-istemci etkileşim paradigmalarını kökten değiştiriyor.

Actions: Form Yönetiminde Devrim

React 19'un amiral gemisi özelliği Actions. Artık <form> elementinin action prop'una doğrudan bir fonksiyon geçebilirsiniz. React, pending state, hata yönetimi ve iyimser güncellemeleri otomatik olarak yönetiyor:

tsx
1function ContactForm() {
2  const [state, submitAction, isPending] = useActionState(
3    async (previousState, formData) => {
4      const name = formData.get('name') as string;
5      const email = formData.get('email') as string;
6      const error = await sendMessage({ name, email });
7      if (error) return { error };
8      return { success: true };
9    },
10    null
11  );
12
13  return (
14    <form action={submitAction}>
15      <input name="name" required />
16      <input name="email" type="email" required />
17      <button disabled={isPending}>
18        {isPending ? 'Gönderiliyor...' : 'Gönder'}
19      </button>
20      {state?.error && <p className="error">{state.error}</p>}
21      {state?.success && <p className="success">Mesajınız gönderildi!</p>}
22    </form>
23  );
24}

Bu yaklaşımın güzelliği, form JavaScript yüklenmeden önce de çalışıyor (progressive enhancement). useActionState hook'u hem client hem de server actions ile uyumlu.

useOptimistic: Anlık UI Güncellemeleri

Yeni useOptimistic hook'u, sunucu yanıtı gelmeden önce UI'ı güncellemenizi sağlıyor. Sosyal medya beğeni butonu veya sepete ekleme gibi işlemler için ideal:

tsx
1function LikeButton({ postId, initialLikes }: { postId: string, initialLikes: number }) {
2  const [optimisticLikes, addOptimisticLike] = useOptimistic(
3    initialLikes,
4    (current: number) => current + 1
5  );
6
7  async function handleLike() {
8    addOptimisticLike(null); // UI anında güncellenir
9    await likePost(postId);  // Sunucu isteği arka planda
10  }
11
12  return (
13    <button onClick={handleLike}>
14      ❤️ {optimisticLikes}
15    </button>
16  );
17}

Sunucu isteği başarısız olursa React otomatik olarak önceki değere geri döner—hiçbir ekstra kod yazmaya gerek yok.

use Hook: Promise ve Context Okuma

Yeni use hook'u, React'ın diğer hook'larından farklı olarak koşullu bloklar ve döngüler içinde çağrılabilir. Promise ve context okuma işlemlerini radikal şekilde basitleştiriyor:

tsx
1import { use, Suspense } from 'react';
2
3// Promise okuma - Suspense ile otomatik entegre
4function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
5  const user = use(userPromise);
6  return <h1>{user.name}</h1>;
7}
8
9// Koşullu context okuma - useContext ile mümkün değildi!
10function ThemeButton({ showIcon }: { showIcon: boolean }) {
11  if (showIcon) {
12    const theme = use(ThemeContext); // Koşullu blokta çağrılabilir
13    return <Icon color={theme.primary} />;
14  }
15  return <button>Tıkla</button>;
16}
17
18// Kullanım
19function App() {
20  const userPromise = fetchUser(); // await yok!
21  return (
22    <Suspense fallback={<Skeleton />}>
23      <UserProfile userPromise={userPromise} />
24    </Suspense>
25  );
26}

Server Components ve Server Actions

Server Components artık stabil ve resmi olarak React'ın çekirdek parçası. Sunucuda render edilen bu bileşenler, client bundle'a dahil edilmiyor:

tsx
1// Server Component - veritabanına doğrudan erişim
2// Bu bileşen sunucuda çalışır, client'a JS göndermez
3async function BlogPosts() {
4  const posts = await db.posts.findMany({
5    orderBy: { createdAt: 'desc' },
6    take: 10
7  });
8  
9  return (
10    <ul>
11      {posts.map(post => (
12        <li key={post.id}>
13          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
14        </li>
15      ))}
16    </ul>
17  );
18}

Server Actions, "use server" direktifi ile tanımlanan ve istemciden güvenli şekilde çağrılabilen sunucu fonksiyonları:

tsx
1// app/actions.ts
2'use server';
3
4export async function createPost(formData: FormData) {
5  const title = formData.get('title') as string;
6  const content = formData.get('content') as string;
7  
8  // Sunucuda çalışır - veritabanına doğrudan erişim
9  await db.posts.create({ data: { title, content } });
10  revalidatePath('/blog');
11}
12
13// Client Component'tan kullanım
14'use client';
15import { createPost } from './actions';
16
17function NewPostForm() {
18  return (
19    <form action={createPost}>
20      <input name="title" placeholder="Başlık" />
21      <textarea name="content" placeholder="İçerik" />
22      <button type="submit">Oluştur</button>
23    </form>
24  );
25}

ref Artık Bir Prop

React 19'da forwardRef wrapper'ına artık gerek yok. ref doğrudan prop olarak geçilebilir:

tsx
1// React 18 - forwardRef gerekli
2const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
3  return <input ref={ref} {...props} />;
4});
5
6// React 19 - doğrudan prop
7function Input({ ref, ...props }: InputProps & { ref?: React.Ref<HTMLInputElement> }) {
8  return <input ref={ref} {...props} />;
9}
10
11// Ref callback cleanup
12function MeasuredDiv() {
13  return (
14    <div ref={(node) => {
15      // Node oluşturulduğunda
16      if (node) measureElement(node);
17      
18      // Cleanup fonksiyonu - node kaldırılırken
19      return () => cleanupMeasurement();
20    }}>
21      İçerik
22    </div>
23  );
24}

Document Metadata ve Stylesheet Desteği

Artık <title>, <meta> ve <link> etiketlerini doğrudan bileşen içinden render edebilirsiniz:

tsx
1function BlogPost({ post }: { post: Post }) {
2  return (
3    <article>
4      <title>{post.title} | Blog</title>
5      <meta name="description" content={post.excerpt} />
6      <meta property="og:title" content={post.title} />
7      <link rel="canonical" href={`https://siyaz.com.tr/blog/${post.slug}`} />
8      
9      <h1>{post.title}</h1>
10      <p>{post.content}</p>
11    </article>
12  );
13}
14// React bunları otomatik olarak <head> içine taşır (hoisting)

Önceki Sürümlerle Karşılaştırma

ÖzellikReact 18React 19
Form yönetimiManuel state + handleruseActionState + Actions
İyimser güncellemeKendi implementasyonunuseOptimistic
Promise okumauseEffect + stateuse hook
Ref geçirmeforwardRef wrapperDoğrudan prop
Metadatareact-helmet / next/headNative hoisting
Server ComponentsFramework-dependentReact core
Context okumauseContext (koşulsuz)use (koşullu da olabilir)
Ref cleanupDesteklenmiyorCallback return

React Compiler (Deneysel)

React Compiler, useMemo, useCallback ve React.memo ihtiyacını ortadan kaldıran bir build-time optimizasyon aracı:

tsx
1// React 18 - Manuel memoization
2function ProductList({ products, onSelect }) {
3  const sorted = useMemo(
4    () => products.sort((a, b) => a.price - b.price),
5    [products]
6  );
7  const handleSelect = useCallback(
8    (id) => onSelect(id),
9    [onSelect]
10  );
11  return sorted.map(p => <Product key={p.id} item={p} onSelect={handleSelect} />);
12}
13
14// React 19 + Compiler - Otomatik optimizasyon
15function ProductList({ products, onSelect }) {
16  const sorted = products.sort((a, b) => a.price - b.price);
17  const handleSelect = (id) => onSelect(id);
18  return sorted.map(p => <Product key={p.id} item={p} onSelect={handleSelect} />);
19}
20// Compiler, gerekli yerlere otomatik memoization ekler

Instagram.com'da production'da test edildi ve olumlu sonuçlar alındı.

Sonuç

React 19, kütüphanenin sunucu taraflı render ve form yönetimi vizyonunu somutlaştıran tarihi bir sürüm. Özellikle Next.js 15 ve Remix gibi framework'lerle birlikte kullanıldığında tam potansiyelini ortaya koyuyor.

Geliştiriciler için en büyük değişiklik, mental model. React artık "sadece UI kütüphanesi" değil—sunucu ve istemci arasında sorunsuz veri akışı sağlayan full-stack bir çözüm. AI kod editörleri de React 19 pattern'larını hızla öğreniyorlar.

Kaynaklar: