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:

function ContactForm() {
  const [state, submitAction, isPending] = useActionState(
    async (previousState, formData) => {
      const name = formData.get('name') as string;
      const email = formData.get('email') as string;
      const error = await sendMessage({ name, email });
      if (error) return { error };
      return { success: true };
    },
    null
  );

  return (
    <form action={submitAction}>
      <input name="name" required />
      <input name="email" type="email" required />
      <button disabled={isPending}>
        {isPending ? 'Gönderiliyor...' : 'Gönder'}
      </button>
      {state?.error && <p className="error">{state.error}</p>}
      {state?.success && <p className="success">Mesajınız gönderildi!</p>}
    </form>
  );
}

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:

function LikeButton({ postId, initialLikes }: { postId: string, initialLikes: number }) {
  const [optimisticLikes, addOptimisticLike] = useOptimistic(
    initialLikes,
    (current: number) => current + 1
  );

  async function handleLike() {
    addOptimisticLike(null); // UI anında güncellenir
    await likePost(postId);  // Sunucu isteği arka planda
  }

  return (
    <button onClick={handleLike}>
      ❤️ {optimisticLikes}
    </button>
  );
}

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:

import { use, Suspense } from 'react';

// Promise okuma - Suspense ile otomatik entegre
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
  const user = use(userPromise);
  return <h1>{user.name}</h1>;
}

// Koşullu context okuma - useContext ile mümkün değildi!
function ThemeButton({ showIcon }: { showIcon: boolean }) {
  if (showIcon) {
    const theme = use(ThemeContext); // Koşullu blokta çağrılabilir
    return <Icon color={theme.primary} />;
  }
  return <button>Tıkla</button>;
}

// Kullanım
function App() {
  const userPromise = fetchUser(); // await yok!
  return (
    <Suspense fallback={<Skeleton />}>
      <UserProfile userPromise={userPromise} />
    </Suspense>
  );
}

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:

// Server Component - veritabanına doğrudan erişim
// Bu bileşen sunucuda çalışır, client'a JS göndermez
async function BlogPosts() {
  const posts = await db.posts.findMany({
    orderBy: { createdAt: 'desc' },
    take: 10
  });
  
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  );
}

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

// app/actions.ts
'use server';

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string;
  const content = formData.get('content') as string;
  
  // Sunucuda çalışır - veritabanına doğrudan erişim
  await db.posts.create({ data: { title, content } });
  revalidatePath('/blog');
}

// Client Component'tan kullanım
'use client';
import { createPost } from './actions';

function NewPostForm() {
  return (
    <form action={createPost}>
      <input name="title" placeholder="Başlık" />
      <textarea name="content" placeholder="İçerik" />
      <button type="submit">Oluştur</button>
    </form>
  );
}

ref Artık Bir Prop

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

// React 18 - forwardRef gerekli
const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
  return <input ref={ref} {...props} />;
});

// React 19 - doğrudan prop
function Input({ ref, ...props }: InputProps & { ref?: React.Ref<HTMLInputElement> }) {
  return <input ref={ref} {...props} />;
}

// Ref callback cleanup
function MeasuredDiv() {
  return (
    <div ref={(node) => {
      // Node oluşturulduğunda
      if (node) measureElement(node);
      
      // Cleanup fonksiyonu - node kaldırılırken
      return () => cleanupMeasurement();
    }}>
      İçerik
    </div>
  );
}

Document Metadata ve Stylesheet Desteği

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

function BlogPost({ post }: { post: Post }) {
  return (
    <article>
      <title>{post.title} | Blog</title>
      <meta name="description" content={post.excerpt} />
      <meta property="og:title" content={post.title} />
      <link rel="canonical" href={`https://siyaz.com.tr/blog/${post.slug}`} />
      
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </article>
  );
}
// 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ı:

// React 18 - Manuel memoization
function ProductList({ products, onSelect }) {
  const sorted = useMemo(
    () => products.sort((a, b) => a.price - b.price),
    [products]
  );
  const handleSelect = useCallback(
    (id) => onSelect(id),
    [onSelect]
  );
  return sorted.map(p => <Product key={p.id} item={p} onSelect={handleSelect} />);
}

// React 19 + Compiler - Otomatik optimizasyon
function ProductList({ products, onSelect }) {
  const sorted = products.sort((a, b) => a.price - b.price);
  const handleSelect = (id) => onSelect(id);
  return sorted.map(p => <Product key={p.id} item={p} onSelect={handleSelect} />);
}
// 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: