React Native App-Entwicklung 2026: Vollständiger Leitfaden und Interview-Fragen

Der komplette Leitfaden zur React Native App-Entwicklung im Jahr 2026. JSI, Fabric, New Architecture, Performance-Optimierung und häufige Interview-Fragen für Entwickler.

React Native App-Entwicklung 2026 - Vollständiger Leitfaden

Die React Native App-Entwicklung hat sich im Jahr 2026 grundlegend verändert. Mit Version 0.87 ist die New Architecture nun die einzige unterstützte Option. Die alte Bridge, die jeden JavaScript-zu-Native-Aufruf als JSON serialisierte, existiert nicht mehr. An ihre Stelle tritt JSI (JavaScript Interface) für direkte synchrone Kommunikation.

Änderungen in React Native 0.87

React Native 0.87 macht die New Architecture obligatorisch. Die alte Bridge wurde vollständig entfernt. Komplexes Listen-Rendering läuft 43% schneller, Scroll-Frame-Drops sanken um 95%, und der Speicherverbrauch reduzierte sich um 33% in Benchmark-Tests.

JSI und die New Architecture verstehen

JSI (JavaScript Interface) ersetzt die asynchrone Bridge durch direkte C++-Bindungen zwischen JavaScript und nativem Code. Anstatt Daten zu JSON zu serialisieren, sie durch eine Nachrichten-Queue zu leiten und auf der anderen Seite zu deserialisieren, ermöglicht JSI JavaScript, Referenzen auf native Objekte zu halten und deren Methoden direkt aufzurufen.

Dieser architektonische Wandel ermöglicht drei Kernfähigkeiten: synchrone Native-Aufrufe, geteiltes Ownership von Objekten zwischen JavaScript- und Native-Schichten sowie Lazy Loading von Native-Modulen.

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

export interface Spec extends TurboModule {
  getUserProfile(userId: string): Promise<{
    id: string;
    name: string;
    email: string;
  }>;
  
  // Synchroner Aufruf - nur mit JSI möglich
  getDeviceLocale(): string;
}

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

Die getDeviceLocale()-Methode gibt sofort zurück, ohne auf ein Promise zu warten. Dies war mit der alten Bridge unmöglich, wo jeder Native-Aufruf asynchrone Serialisierung erforderte.

Produktionsreife Komponenten mit Fabric erstellen

Fabric ist das neue Rendering-System, das zusammen mit JSI arbeitet. Es verwaltet den UI-Baum in C++ und synchronisiert direkt mit dem JavaScript-Thread, wodurch das "UI-Jank" eliminiert wird, das auftrat, wenn die alte Bridge bei schnellen Updates nicht mitkam.

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}
    >
      <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)}
        </Text>
        {!product.inStock && (
          <Text style={styles.outOfStock}>Nicht verfügbar</Text>
        )}
      </View>
    </AnimatedPressable>
  );
});

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

Die Kombination aus memo, useCallback und useSharedValue stellt sicher, dass Animationen auf dem UI-Thread laufen, ohne den JavaScript-Thread zu blockieren. react-native-reanimated nutzt Fabric direkt an und kann Animationen mit 60+ FPS ausführen.

State Management mit Zustand

Zustand hat sich als bevorzugte State-Management-Lösung für React Native etabliert. Der minimale Boilerplate und die Kompatibilität mit Concurrent React machen es ideal für mobile Anwendungen.

stores/cartStore.tstypescript
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';

interface CartItem {
  productId: string;
  quantity: number;
  price: number;
}

interface CartStore {
  items: CartItem[];
  addItem: (productId: string, price: number) => void;
  removeItem: (productId: string) => void;
  updateQuantity: (productId: string, quantity: number) => void;
  clearCart: () => void;
  total: () => number;
}

export const useCartStore = create<CartStore>()(
  persist(
    (set, get) => ({
      items: [],
      
      addItem: (productId, price) => set((state) => {
        const existing = state.items.find(i => i.productId === productId);
        if (existing) {
          return {
            items: state.items.map(i =>
              i.productId === productId
                ? { ...i, quantity: i.quantity + 1 }
                : i
            ),
          };
        }
        return {
          items: [...state.items, { productId, quantity: 1, price }],
        };
      }),
      
      removeItem: (productId) => set((state) => ({
        items: state.items.filter(i => i.productId !== productId),
      })),
      
      updateQuantity: (productId, quantity) => set((state) => ({
        items: quantity > 0
          ? state.items.map(i =>
              i.productId === productId ? { ...i, quantity } : i
            )
          : state.items.filter(i => i.productId !== productId),
      })),
      
      clearCart: () => set({ items: [] }),
      
      total: () => {
        return get().items.reduce(
          (sum, item) => sum + item.price * item.quantity,
          0
        );
      },
    }),
    {
      name: 'cart-storage',
      storage: createJSONStorage(() => AsyncStorage),
    }
  )
);

Der Store persistiert den Warenkorb in AsyncStorage und stellt automatisch den Zustand wieder her, wenn die App neu gestartet wird. Die Middleware-Komposition macht dies mit minimalem Setup möglich.

Expo Router bringt dateibasiertes Routing zu React Native. Die Ordnerstruktur definiert die App-Navigation, ähnlich wie Next.js im Web-Ökosystem.

app/_layout.tsxtypescript
import { Stack } from 'expo-router';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { GestureHandlerRootView } from 'react-native-gesture-handler';

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60 * 5,
      retry: 2,
    },
  },
});

export default function RootLayout() {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <QueryClientProvider client={queryClient}>
        <Stack
          screenOptions={{
            headerShown: false,
            animation: 'slide_from_right',
          }}
        />
      </QueryClientProvider>
    </GestureHandlerRootView>
  );
}
app/(tabs)/_layout.tsxtypescript
import { Tabs } from 'expo-router';
import { Home, Search, ShoppingCart, User } from 'lucide-react-native';

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

Datenabfragen mit TanStack Query

TanStack Query (ehemals React Query) übernimmt das Server-State-Management. Die Bibliothek kümmert sich um Caching, Revalidierung und Hintergrund-Updates, während Entwickler sich auf die UI konzentrieren können.

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

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

export function useProducts(category?: string) {
  return useQuery({
    queryKey: ['products', category],
    queryFn: () => api.get<Product[]>(`/products`, {
      params: category ? { category } : undefined,
    }),
    staleTime: 1000 * 60 * 5,
  });
}

export function useProduct(id: string) {
  return useQuery({
    queryKey: ['product', id],
    queryFn: () => api.get<Product>(`/products/${id}`),
    enabled: !!id,
  });
}

export function useUpdateProduct() {
  const queryClient = useQueryClient();
  
  return useMutation({
    mutationFn: (data: Partial<Product> & { id: string }) =>
      api.patch<Product>(`/products/${data.id}`, data),
    onSuccess: (updatedProduct) => {
      queryClient.setQueryData(
        ['product', updatedProduct.id],
        updatedProduct
      );
      queryClient.invalidateQueries({ queryKey: ['products'] });
    },
  });
}

Performance-Optimierung für Listen

FlashList von Shopify ersetzt FlatList für hochperformante Listenansichten. Die Bibliothek recycelt Komponenten aggressiv und nutzt die Fabric-Architektur für flüssiges Scrollen.

components/ProductList.tsxtypescript
import React, { useCallback } from 'react';
import { View, StyleSheet, RefreshControl } from 'react-native';
import { FlashList } from '@shopify/flash-list';
import { useProducts } from '../hooks/useProducts';
import { ProductCard } from './ProductCard';
import { ProductSkeleton } from './ProductSkeleton';

interface ProductListProps {
  category?: string;
  onProductPress: (id: string) => void;
}

export function ProductList({ category, onProductPress }: ProductListProps) {
  const {
    data: products,
    isLoading,
    isRefetching,
    refetch,
  } = useProducts(category);

  const renderItem = useCallback(
    ({ item }: { item: Product }) => (
      <ProductCard product={item} onPress={onProductPress} />
    ),
    [onProductPress]
  );

  const keyExtractor = useCallback(
    (item: Product) => item.id,
    []
  );

  if (isLoading) {
    return (
      <View style={styles.skeletonContainer}>
        {Array.from({ length: 6 }).map((_, i) => (
          <ProductSkeleton key={i} />
        ))}
      </View>
    );
  }

  return (
    <FlashList
      data={products}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      estimatedItemSize={280}
      numColumns={2}
      contentContainerStyle={styles.listContent}
      refreshControl={
        <RefreshControl
          refreshing={isRefetching}
          onRefresh={refetch}
          tintColor="#2563eb"
        />
      }
      ItemSeparatorComponent={() => <View style={styles.separator} />}
    />
  );
}

const styles = StyleSheet.create({
  listContent: {
    padding: 16,
  },
  separator: {
    height: 16,
  },
  skeletonContainer: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    padding: 16,
    gap: 16,
  },
});

Die estimatedItemSize-Eigenschaft ist entscheidend für die Performance. FlashList nutzt diesen Wert für initiales Layout und passt sich dann basierend auf tatsächlichen Messungen an.

Häufige Interview-Fragen für React Native Entwickler

Bei Bewerbungsgesprächen für React Native-Positionen werden bestimmte Themen regelmäßig abgefragt. Die folgenden Fragen und Antworten decken die wichtigsten Bereiche ab.

Was ist der Unterschied zwischen der alten Bridge und JSI?

Die alte Bridge verwendete asynchrone JSON-Serialisierung für die Kommunikation zwischen JavaScript und Native. JSI ermöglicht direkte C++-Bindungen, synchrone Aufrufe und geteiltes Object-Ownership. Dies eliminiert den Serialisierungs-Overhead und ermöglicht echte native Module.

Wie funktioniert Fabric im Vergleich zum alten Renderer?

Fabric rendert UI-Bäume in C++ statt in Java/Objective-C. Dies ermöglicht synchrone Messungen, priorisierte Updates und direkte Integration mit JSI. Der Shadow-Tree lebt jetzt auf dem C++-Layer, was die Kommunikation zwischen Threads drastisch reduziert.

Wann sollte man useCallback und useMemo verwenden?

useCallback sollte für Event-Handler verwendet werden, die an Kind-Komponenten übergeben werden. useMemo ist sinnvoll für teure Berechnungen, die von Props oder State abhängen. Beide sollten sparsam eingesetzt werden, da sie eigenen Overhead haben.

Wie optimiert man die Performance einer FlatList?

FlashList als Alternative zu FlatList verwenden, getItemLayout oder estimatedItemSize bereitstellen, removeClippedSubviews aktivieren, List-Items mit memo wrappen und keyExtractor außerhalb der Render-Funktion definieren.

Bereit für deine React Native-Interviews?

Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.

Fazit

Die React Native App-Entwicklung im Jahr 2026 erfordert ein Verständnis der New Architecture mit JSI und Fabric. Die Kombination aus Expo Router für Navigation, TanStack Query für Server-State und Zustand für Client-State bildet ein solides Fundament für produktionsreife mobile Anwendungen. FlashList und react-native-reanimated sorgen für die Performance, die Nutzer von nativen Apps erwarten. Entwickler, die diese Technologien beherrschen, sind bestens für aktuelle React Native-Projekte und Vorstellungsgespräche vorbereitet.

Tägliche Challenge

Findest du den Bug in React Native?

Ein echter Codeausschnitt, ein versteckter Bug, ein Versuch pro Tag. Zum Ausprobieren ohne Konto.

Anthony Fillion-Maillet

Geschrieben von

Anthony Fillion-Maillet

Gründer von SharpSkill

Seit über 10 Jahren Fullstack-Entwickler. Er leitet SharpSkill und verantwortet alles, was hier erscheint.

Aktualisiert am 6. September 2026

Tags

#react-native
#mobile-development
#javascript
#typescript
#jsi
#fabric

Teilen

Verwandte Artikel