2026'da React Native Uygulama Geliştirme: Kapsamlı Kılavuz ve Mülakat Soruları

2026'da React Native uygulama geliştirmeyi Yeni Mimari, JSI, Fabric ve TurboModules ile öğrenin. Kod örnekleri ve mülakat soruları içeren pratik tutorial.

2026'da React Native Uygulama Geliştirme: Kapsamlı Kılavuz ve Mülakat Soruları

2026'da React Native uygulama geliştirme, 0.87 sürümüyle birlikte köklü bir dönüşüm geçirdi. Yeni Mimari artık desteklenen tek seçenek olarak sunuluyor. Her JavaScript-native çağrısını JSON olarak serileştiren eski bridge tamamen kaldırıldı ve yerini doğrudan senkron iletişim sağlayan JSI (JavaScript Interface) aldı.

React Native 0.87'de Neler Değişti

React Native 0.87, Yeni Mimari'yi zorunlu kılıyor. Eski bridge tamamen kaldırıldı. Karmaşık liste render işlemleri %43 daha hızlı çalışıyor, kaydırma sırasında kare düşmeleri %95 azaldı ve benchmark testlerinde bellek kullanımı %33 düştü.

JSI ve Yeni Mimariyi Anlamak

JSI (JavaScript Interface), asenkron bridge'i JavaScript ve native kod arasında doğrudan C++ bağlamalarıyla değiştiriyor. Verileri JSON'a serileştirmek, mesaj kuyruğundan geçirmek ve diğer tarafta deserialize etmek yerine, JSI JavaScript'in native nesnelere referans tutmasına ve metodlarını doğrudan çağırmasına olanak tanıyor.

Bu mimari değişiklik üç temel yeteneği mümkün kılıyor: senkron native çağrılar, JavaScript ve native katmanlar arasında paylaşımlı nesne sahipliği ve native modüllerin tembel yüklenmesi.

NativeUserModule.tstypescript
import { TurboModuleRegistry, TurboModule } from 'react-native';

export interface Spec extends TurboModule {
  getUserProfile(userId: string): Promise<{
    id: string;
    name: string;
    email: string;
  }>;
  
  // Senkron çağrı - sadece JSI ile mümkün
  getDeviceLocale(): string;
}

export default TurboModuleRegistry.getEnforcing<Spec>('UserModule');

getDeviceLocale() metodu Promise beklemeden anında sonuç döndürüyor. Bu, her native çağrının asenkron serileştirme gerektirdiği eski bridge ile mümkün değildi.

Fabric ile Prodüksiyon Hazır Komponent Oluşturma

Fabric, JSI ile birlikte çalışan yeni render sistemidir. UI ağacını C++ içinde yönetiyor ve JavaScript thread'iyle doğrudan senkronize oluyor, böylece eski bridge'in hızlı güncellemeler sırasında geride kalmasıyla oluşan "UI takılmalarını" ortadan kaldırıyor.

ProductCard.tsxtypescript
import React, { memo, useCallback } from 'react';
import {
  View,
  Text,
  Image,
  Pressable,
  StyleSheet,
} from 'react-native';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
} from 'react-native-reanimated';

interface Product {
  id: string;
  name: string;
  price: number;
  imageUrl: string;
  inStock: boolean;
}

interface ProductCardProps {
  product: Product;
  onPress: (id: string) => void;
}

const AnimatedPressable = Animated.createAnimatedComponent(Pressable);

export const ProductCard = memo(function ProductCard({
  product,
  onPress,
}: ProductCardProps) {
  const scale = useSharedValue(1);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  const handlePressIn = useCallback(() => {
    scale.value = withSpring(0.95);
  }, [scale]);

  const handlePressOut = useCallback(() => {
    scale.value = withSpring(1);
  }, [scale]);

  const handlePress = useCallback(() => {
    onPress(product.id);
  }, [onPress, product.id]);

  return (
    <AnimatedPressable
      style={[styles.card, animatedStyle]}
      onPressIn={handlePressIn}
      onPressOut={handlePressOut}
      onPress={handlePress}
      accessibilityRole="button"
      accessibilityLabel={`${product.name}, ${product.price} TL`}
    >
      <Image
        source={{ uri: product.imageUrl }}
        style={styles.image}
        resizeMode="cover"
      />
      <View style={styles.content}>
        <Text style={styles.name} numberOfLines={2}>
          {product.name}
        </Text>
        <Text style={styles.price}>{product.price.toFixed(2)} TL</Text>
        {!product.inStock && (
          <Text style={styles.outOfStock}>Stokta Yok</Text>
        )}
      </View>
    </AnimatedPressable>
  );
});

const styles = StyleSheet.create({
  card: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    overflow: 'hidden',
    marginHorizontal: 8,
    marginVertical: 4,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  image: {
    width: '100%',
    height: 160,
  },
  content: {
    padding: 12,
  },
  name: {
    fontSize: 16,
    fontWeight: '600',
    color: '#1a1a1a',
    marginBottom: 4,
  },
  price: {
    fontSize: 18,
    fontWeight: '700',
    color: '#2563eb',
  },
  outOfStock: {
    fontSize: 12,
    color: '#dc2626',
    marginTop: 4,
  },
});

Bu komponent, animasyonları JSI üzerinden UI thread'inde çalıştıran react-native-reanimated kullanıyor. useSharedValue ve useAnimatedStyle hook'ları bridge'den geçmeden doğrudan native kodla iletişim kuruyor.

TanStack Query ile State Yönetimi

React Native uygulamalarında sunucu state'i özel araçlardan faydalanıyor. TanStack Query, global state container gerektirmeden önbellekleme, arka planda yenileme ve iyimser güncellemeleri yönetiyor.

hooks/useProducts.tstypescript
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

interface Product {
  id: string;
  name: string;
  price: number;
  imageUrl: string;
  inStock: boolean;
}

const API_BASE = 'https://api.example.com';

async function fetchProducts(category?: string): Promise<Product[]> {
  const url = category
    ? `${API_BASE}/products?category=${category}`
    : `${API_BASE}/products`;
  
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error('Ürünler getirilemedi');
  }
  return response.json();
}

export function useProducts(category?: string) {
  return useQuery({
    queryKey: ['products', category],
    queryFn: () => fetchProducts(category),
    staleTime: 5 * 60 * 1000, // 5 dakika
    gcTime: 30 * 60 * 1000, // 30 dakika
  });
}

export function useToggleStock() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (productId: string) => {
      const response = await fetch(`${API_BASE}/products/${productId}/toggle-stock`, {
        method: 'POST',
      });
      if (!response.ok) {
        throw new Error('Stok durumu güncellenemedi');
      }
      return response.json();
    },
    // İyimser güncelleme
    onMutate: async (productId) => {
      await queryClient.cancelQueries({ queryKey: ['products'] });
      
      const previousProducts = queryClient.getQueryData<Product[]>(['products']);
      
      queryClient.setQueryData<Product[]>(['products'], (old) =>
        old?.map((p) =>
          p.id === productId ? { ...p, inStock: !p.inStock } : p
        )
      );
      
      return { previousProducts };
    },
    onError: (_err, _productId, context) => {
      if (context?.previousProducts) {
        queryClient.setQueryData(['products'], context.previousProducts);
      }
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ['products'] });
    },
  });
}

onMutate callback'i sunucu yanıtından önce iyimser güncelleme gerçekleştiriyor. Mutasyon başarısız olursa, onError önceki state'i geri yüklüyor. Bu pattern, veri tutarlılığını korurken anında UI geri bildirimi sağlıyor.

React Native mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Expo Router ile Navigasyon

Expo Router, Next.js App Router'a benzer şekilde React Native için dosya tabanlı routing sağlıyor. Dosya yapısı route'ları otomatik olarak tanımlıyor.

app/(tabs)/_layout.tsxtypescript
import { Tabs } from 'expo-router';
import { Home, Search, ShoppingCart, User } from 'lucide-react-native';

export default function TabsLayout() {
  return (
    <Tabs
      screenOptions={{
        tabBarActiveTintColor: '#2563eb',
        tabBarInactiveTintColor: '#6b7280',
        headerShown: false,
      }}
    >
      <Tabs.Screen
        name="index"
        options={{
          title: 'Ana Sayfa',
          tabBarIcon: ({ color, size }) => (
            <Home color={color} size={size} />
          ),
        }}
      />
      <Tabs.Screen
        name="search"
        options={{
          title: 'Ara',
          tabBarIcon: ({ color, size }) => (
            <Search color={color} size={size} />
          ),
        }}
      />
      <Tabs.Screen
        name="cart"
        options={{
          title: 'Sepet',
          tabBarIcon: ({ color, size }) => (
            <ShoppingCart color={color} size={size} />
          ),
        }}
      />
      <Tabs.Screen
        name="profile"
        options={{
          title: 'Profil',
          tabBarIcon: ({ color, size }) => (
            <User color={color} size={size} />
          ),
        }}
      />
    </Tabs>
  );
}

Dinamik route'lar köşeli parantez notasyonu kullanıyor. app/product/[id].tsx konumundaki bir dosya herhangi bir /product/123 yolunu işliyor:

app/product/[id].tsxtypescript
import { useLocalSearchParams } from 'expo-router';
import { View, Text, ActivityIndicator } from 'react-native';
import { useQuery } from '@tanstack/react-query';

export default function ProductDetailScreen() {
  const { id } = useLocalSearchParams<{ id: string }>();

  const { data: product, isLoading, error } = useQuery({
    queryKey: ['product', id],
    queryFn: () => fetchProduct(id),
    enabled: !!id,
  });

  if (isLoading) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <ActivityIndicator size="large" color="#2563eb" />
      </View>
    );
  }

  if (error || !product) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text>Ürün bulunamadı</Text>
      </View>
    );
  }

  return (
    <View style={{ flex: 1, padding: 16 }}>
      <Text style={{ fontSize: 24, fontWeight: 'bold' }}>{product.name}</Text>
      <Text style={{ fontSize: 20, color: '#2563eb' }}>
        {product.price.toFixed(2)} TL
      </Text>
    </View>
  );
}

React Native Mimarisi Hakkında Yaygın Mülakat Soruları

2026'da React Native pozisyonları için teknik mülakatlar büyük ölçüde Yeni Mimari'ye odaklanıyor. Aşağıdaki sorular sıklıkla karşılaşılan sorulardır.

Mülakat Odak Alanları

Mülakatçılar adayların JSI, Fabric ve TurboModules'ı kavramsal düzeyde açıklayabilmesini bekliyor. Sözdizimini ezberlemek, mimarinin neden değiştiğini ve hangi sorunları çözdüğünü anlamaktan daha az önemli.

Soru: JSI nedir ve React Native neden bunu benimsedi?

JSI (JavaScript Interface), JavaScript'in native nesnelere referans tutmasına ve metodlarını doğrudan çağırmasına olanak tanıyan bir C++ katmanıdır. Eski bridge her çağrıyı JSON'a serileştiriyordu, asenkron olarak kuyruğa alıyordu ve native tarafta deserialize ediyordu. Bu gecikme ekliyordu ve senkron işlemleri engelliyordu.

JSI ile bir JavaScript fonksiyonu native bir metodu çağırabilir ve sonucu aynı kare içinde alabilir. Bu, senkron layout ölçümleri ve native view'ların doğrudan manipülasyonu gibi özellikleri mümkün kılıyor.

Soru: Fabric eski renderer'dan nasıl farklılaşıyor?

Fabric, UI ağacını JavaScript yerine native kodda tutan C++ render sistemidir. Eski renderer shadow tree'yi JavaScript'te tutuyordu ve güncelleme batch'lerini bridge üzerinden gönderiyordu.

Fabric'in avantajları:

  • JSI üzerinden senkron layout hesaplamaları
  • Concurrent rendering desteği (React 18 özellikleri düzgün çalışıyor)
  • JS ve native arasında paylaşımlı sahiplikle daha iyi bellek yönetimi
  • Azaltılmış serileştirme overhead'i

Soru: TurboModules nedir?

TurboModules, Native Modules'ın yerini alıyor. Temel farklar:

  1. Tembel yükleme: TurboModules sadece ilk erişimde yükleniyor, başlangıç süresini kısaltıyor
  2. Tip güvenliği: CodeGen, TypeScript spec'lerinden tip güvenli bağlamalar üretiyor
  3. Senkron metodlar: TurboModules gerektiğinde senkron fonksiyonlar sunabiliyor
  4. Doğrudan JSI erişimi: Bridge serileştirmesi yok

Soru: Ne zaman senkron native metod kullanılmalı?

Senkron native metodlar şu tür işlemler için uygundur:

  • Mikrosaniyelerde tamamlanan işlemler (cihaz locale'ini okuma, izin durumunu kontrol etme)
  • UI'ı kasıtlı olarak bloke eden işlemler (navigasyondan önce modal onay)
  • Anında render için gereken değerleri döndüren işlemler

Senkron metodlardan kaçınılması gereken durumlar:

  • Ağ istekleri
  • Küçük okumalar dışındaki dosya I/O işlemleri
  • Veritabanı sorguları
  • 16ms'yi aşan herhangi bir işlem (kareyi bloke eder)

Daha fazla React Native mülakat sorusu için networking ve API modülü ve native modüller bölümü incelenebilir.

React Native Komponentlerini Test Etme

React Native Testing Library, komponentleri kullanıcıların etkileşim kurduğu şekilde test etmek için araçlar sağlıyor ve uygulama detayları yerine erişilebilirlik ve davranışa odaklanıyor.

__tests__/ProductCard.test.tsxtypescript
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react-native';
import { ProductCard } from '../components/ProductCard';

const mockProduct = {
  id: 'prod-1',
  name: 'Kablosuz Kulaklık',
  price: 149.99,
  imageUrl: 'https://example.com/headphones.jpg',
  inStock: true,
};

describe('ProductCard', () => {
  it('ürün bilgilerini gösterir', () => {
    const onPress = jest.fn();
    render(<ProductCard product={mockProduct} onPress={onPress} />);

    expect(screen.getByText('Kablosuz Kulaklık')).toBeOnTheScreen();
    expect(screen.getByText('149.99 TL')).toBeOnTheScreen();
  });

  it('basıldığında onPress fonksiyonunu ürün id ile çağırır', () => {
    const onPress = jest.fn();
    render(<ProductCard product={mockProduct} onPress={onPress} />);

    fireEvent.press(
      screen.getByRole('button', { name: /kablosuz kulaklık/i })
    );

    expect(onPress).toHaveBeenCalledWith('prod-1');
    expect(onPress).toHaveBeenCalledTimes(1);
  });

  it('ürün mevcut olmadığında stokta yok mesajı gösterir', () => {
    const outOfStockProduct = { ...mockProduct, inStock: false };
    render(<ProductCard product={outOfStockProduct} onPress={jest.fn()} />);

    expect(screen.getByText('Stokta Yok')).toBeOnTheScreen();
  });
});

Testler, test ID'leri veya komponent içi detaylar yerine metin içeriği ve erişilebilirlik rolleriyle sorgulama yapıyor. Bu yaklaşım, refactoring'e karşı dayanıklı kalırken kullanıcıları etkileyen regresyonları yakalıyor.

Prodüksiyonda Performans İzleme

React Native 0.87, prodüksiyon performans izleme için Sentry ve benzeri araçlarla entegre oluyor. İzlenecek temel metrikler:

  • Time to Interactive (TTI): Uygulamanın kullanıcı girdisine yanıt verene kadar geçen süre
  • Kare düşmeleri: 16.67ms'den uzun süren render kareları
  • JavaScript thread kullanımı: Yüksek kullanım, UI'ı bloke eden pahalı hesaplamaları gösterir
  • Bellek artışı: Sürekli artış memory leak'leri işaret eder
app/_layout.tsxtypescript
import * as Sentry from '@sentry/react-native';
import { useEffect } from 'react';
import { AppState, AppStateStatus } from 'react-native';

Sentry.init({
  dsn: process.env.EXPO_PUBLIC_SENTRY_DSN,
  tracesSampleRate: 0.2,
  profilesSampleRate: 0.1,
  enableAutoPerformanceTracing: true,
});

export default function RootLayout() {
  useEffect(() => {
    const subscription = AppState.addEventListener(
      'change',
      (state: AppStateStatus) => {
        if (state === 'active') {
          Sentry.addBreadcrumb({
            category: 'app.lifecycle',
            message: 'Uygulama aktif oldu',
            level: 'info',
          });
        }
      }
    );

    return () => subscription.remove();
  }, []);

  // ... layout'un geri kalanı
}

2026'da React Native Geliştirme İçin Önemli Çıkarımlar

  • Yeni Mimari (JSI, Fabric, TurboModules) React Native 0.87'de zorunlu. Eski bridge artık mevcut değil.
  • JSI senkron native çağrıları mümkün kılıyor. 16ms'nin altındaki işlemler için dikkatli kullanılmalı.
  • Fabric, UI'ı C++ içinde render ediyor ve JSI üzerinden JavaScript ile senkronize oluyor. Bu, asenkron render darboğazını ortadan kaldırıyor.
  • TurboModules tembel yükleniyor ve TypeScript spec'lerinden üretilen tip güvenli bağlamalar sağlıyor.
  • Expo Router, Next.js App Router'a benzer dosya tabanlı navigasyon sunuyor.
  • React Native Testing Library, komponentleri public API'ları ve erişilebilirlik ağacı üzerinden test ediyor.
  • Prodüksiyon uygulamaları TTI, kare düşmeleri ve bellek kullanımını ilk günden izlemeli.

Tam uygulama oluşturmaya daha derin bir bakış için React Native tam uygulama tutorial incelenebilir. Yeni Mimari kılavuzu eski sürümlerden geçişi kapsıyor.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Günün meydan okuması

React Native kodundaki hatayı bulabilir misin?

Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Anthony Fillion-Maillet

Yazan:

Anthony Fillion-Maillet

SharpSkill kurucusu

10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.

6 Eylül 2026 tarihinde güncellendi

Paylaş

İlgili makaleler