# React Native: Eine vollständige Mobile App entwickeln (2026) > Umfassende Anleitung zur Entwicklung von iOS- und Android-Apps mit React Native. Vom Setup bis zum Deployment -- alle Grundlagen für den Einstieg. - Published: 2026-01-10 - Updated: 2026-04-06 - Author: SharpSkill - Tags: react native, mobile development, javascript, ios, android - Reading time: 15 min --- Mit React Native lassen sich native Mobile Apps für iOS und Android aus einer einzigen JavaScript-Codebasis heraus erstellen. Das von Meta gepflegte Framework wird unter anderem von Instagram, Facebook und Discord eingesetzt und verbindet schnelle Entwicklungszyklen mit leistungsstarken Anwendungen. > **Warum React Native im Jahr 2026?** > > Die neue Architektur (Fabric und TurboModules) ist inzwischen stabil und liefert nahezu native Performance bei gleichzeitig hoher Entwicklerproduktivität. Über 40 % der 500 meistgenutzten Apps setzen auf React Native. ## Development Environment Setup Bevor es losgeht, müssen die notwendigen Werkzeuge installiert werden. React Native bietet zwei Ansätze: Expo (empfohlen für den Einstieg) und die React Native CLI (für mehr Kontrolle). ```bash # setup.sh # Node.js installation (LTS version recommended) # Check installed version node --version # >= 18.x required npm --version # >= 9.x required # Install Expo CLI tool globally npm install -g expo-cli # Create a new project with Expo npx create-expo-app@latest MyApp --template blank-typescript # Navigate to the project cd MyApp # Start the development server npx expo start ``` Expo vereinfacht die Entwicklung erheblich, da es sich automatisch um die native Konfiguration kümmert. Zum Testen der App genügt die Expo-Go-App auf dem Smartphone -- der angezeigte QR-Code wird einfach gescannt. ```bash # structure.sh # Generated project structure MyApp/ ├── App.tsx # Application entry point ├── app.json # Expo configuration ├── package.json # Dependencies ├── tsconfig.json # TypeScript configuration ├── babel.config.js # Babel configuration └── assets/ # Images and resources ├── icon.png └── splash.png ``` ## Core React Native Components React Native stellt native Komponenten bereit, die HTML-Elemente ersetzen. Jede Komponente wird direkt in eine native iOS- oder Android-Komponente übersetzt. ```tsx // App.tsx import React from 'react'; import { View, Text, StyleSheet, SafeAreaView, StatusBar } from 'react-native'; // Main application component export default function App() { return ( // SafeAreaView prevents overlap with status bar {/* StatusBar configures system bar appearance */} {/* View is the equivalent of div */} {/* Text is required to display text */} Welcome to MyApp A React Native application ); } // StyleSheet.create optimizes styles for native const styles = StyleSheet.create({ container: { flex: 1, // Takes all available space backgroundColor: '#ffffff', }, header: { padding: 20, alignItems: 'center', // Centers horizontally justifyContent: 'center', // Centers vertically }, title: { fontSize: 24, fontWeight: 'bold', color: '#1a1a1a', marginBottom: 8, }, subtitle: { fontSize: 16, color: '#666666', }, }); ``` > **Flexbox als Standard** > > React Native verwendet Flexbox standardmässig mit `flexDirection: 'column'` (im Gegensatz zum Web, das `row` nutzt). Dieser Unterschied ist beim Layout entscheidend. ## Handling User Interactions Touch-Interaktionen werden über spezialisierte Komponenten gesteuert. Für jeden Interaktionstyp gibt es eine eigene Komponente, die auf Performance optimiert ist. ```tsx // components/InteractiveButton.tsx import React, { useState } from 'react'; import { TouchableOpacity, TouchableHighlight, Pressable, Text, StyleSheet, View, } from 'react-native'; // Button component with different interaction styles export function InteractiveButton() { const [count, setCount] = useState(0); return ( {/* TouchableOpacity reduces opacity on touch */} setCount(c => c + 1)} > Counter: {count} {/* Pressable offers more control over states */} [ styles.button, styles.pressableButton, pressed && styles.buttonPressed, ]} onPress={() => console.log('Pressed!')} onLongPress={() => console.log('Long press!')} > {({ pressed }) => ( {pressed ? 'Pressed!' : 'Press here'} )} ); } const styles = StyleSheet.create({ container: { gap: 16, padding: 20, }, button: { backgroundColor: '#007AFF', paddingVertical: 14, paddingHorizontal: 28, borderRadius: 10, alignItems: 'center', }, pressableButton: { backgroundColor: '#34C759', }, buttonPressed: { backgroundColor: '#2DA44E', transform: [{ scale: 0.98 }], }, buttonText: { color: '#ffffff', fontSize: 16, fontWeight: '600', }, }); ``` ## Screen Navigation with React Navigation Navigation ist für jede Mobile App unverzichtbar. React Navigation ist die Standardlösung und bietet verschiedene Navigationstypen, die auf mobile Nutzungsmuster zugeschnitten sind. ```bash # install-navigation.sh # Installing navigation dependencies npx expo install @react-navigation/native npx expo install @react-navigation/native-stack npx expo install react-native-screens react-native-safe-area-context ``` ```tsx // App.tsx import React from 'react'; import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; // Screen imports import { HomeScreen } from './screens/HomeScreen'; import { DetailScreen } from './screens/DetailScreen'; import { ProfileScreen } from './screens/ProfileScreen'; // Type definition for TypeScript navigation export type RootStackParamList = { Home: undefined; // No parameters Detail: { itemId: number; title: string }; // Required parameters Profile: { userId?: string }; // Optional parameter }; // Creating typed navigator const Stack = createNativeStackNavigator(); export default function App() { return ( // NavigationContainer manages navigation state ({ title: route.params.title })} /> ); } ``` ```tsx // screens/HomeScreen.tsx import React from 'react'; import { View, Text, FlatList, TouchableOpacity, StyleSheet } from 'react-native'; import { NativeStackScreenProps } from '@react-navigation/native-stack'; import { RootStackParamList } from '../App'; // Typing navigation props type Props = NativeStackScreenProps; // Sample data const ITEMS = [ { id: 1, title: 'First item' }, { id: 2, title: 'Second item' }, { id: 3, title: 'Third item' }, ]; export function HomeScreen({ navigation }: Props) { return ( {/* FlatList for performant lists */} item.id.toString()} renderItem={({ item }) => ( { // Navigation with typed parameters navigation.navigate('Detail', { itemId: item.id, title: item.title, }); }} > {item.title} )} ItemSeparatorComponent={() => } /> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#f5f5f5', }, item: { backgroundColor: '#ffffff', padding: 20, }, itemText: { fontSize: 16, color: '#1a1a1a', }, separator: { height: 1, backgroundColor: '#e0e0e0', }, }); ``` ## State Management with Context and Hooks Für einfaches bis mittelkomplexes State Management bietet React Context in Kombination mit Hooks eine wirkungsvolle Lösung ohne externe Abhängigkeiten. ```tsx // context/AuthContext.tsx import React, { createContext, useContext, useState, useCallback } from 'react'; // Types for authentication interface User { id: string; email: string; name: string; } interface AuthContextType { user: User | null; isLoading: boolean; signIn: (email: string, password: string) => Promise; signOut: () => void; } // Creating context with default value const AuthContext = createContext(undefined); // Provider that wraps the application export function AuthProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState(null); const [isLoading, setIsLoading] = useState(false); // Sign in function const signIn = useCallback(async (email: string, password: string) => { setIsLoading(true); try { // Simulated API call const response = await fetch('https://api.example.com/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), }); const data = await response.json(); setUser(data.user); } catch (error) { console.error('Login error:', error); throw error; } finally { setIsLoading(false); } }, []); // Sign out function const signOut = useCallback(() => { setUser(null); }, []); return ( {children} ); } // Custom hook to use the context export function useAuth() { const context = useContext(AuthContext); if (context === undefined) { throw new Error('useAuth must be used within an AuthProvider'); } return context; } ``` ```tsx // screens/LoginScreen.tsx import React, { useState } from 'react'; import { View, Text, TextInput, TouchableOpacity, StyleSheet, ActivityIndicator, Alert, } from 'react-native'; import { useAuth } from '../context/AuthContext'; export function LoginScreen() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const { signIn, isLoading } = useAuth(); // Form submission handler const handleSubmit = async () => { if (!email || !password) { Alert.alert('Error', 'Please fill in all fields'); return; } try { await signIn(email, password); } catch (error) { Alert.alert('Error', 'Invalid credentials'); } }; return ( Login {isLoading ? ( ) : ( Sign In )} ); } const styles = StyleSheet.create({ container: { flex: 1, padding: 20, justifyContent: 'center', backgroundColor: '#ffffff', }, title: { fontSize: 28, fontWeight: 'bold', marginBottom: 32, textAlign: 'center', }, input: { borderWidth: 1, borderColor: '#e0e0e0', borderRadius: 10, padding: 16, marginBottom: 16, fontSize: 16, backgroundColor: '#f9f9f9', }, button: { backgroundColor: '#007AFF', padding: 16, borderRadius: 10, alignItems: 'center', marginTop: 8, }, buttonDisabled: { backgroundColor: '#99c9ff', }, buttonText: { color: '#ffffff', fontSize: 18, fontWeight: '600', }, }); ``` > **Globaler vs. lokaler State** > > Bei komplexeren Anwendungen mit umfangreichem geteiltem State können Lösungen wie Zustand oder Redux Toolkit sinnvoller sein. Context eignet sich optimal für State, der sich selten ändert (Theme, Authentifizierung). ## API Calls and Data Management Die Kommunikation mit dem Backend ist ein zentraler Bestandteil jeder Mobile App. Das folgende Muster nutzt eine Abstraktionsschicht für robuste API-Aufrufe. ```tsx // services/api.ts // Base API configuration const API_BASE_URL = 'https://api.example.com'; // Type for API errors interface ApiError { message: string; code: string; status: number; } // Utility function for requests async function request( endpoint: string, options: RequestInit = {} ): Promise { const url = `${API_BASE_URL}${endpoint}`; const config: RequestInit = { ...options, headers: { 'Content-Type': 'application/json', ...options.headers, }, }; try { const response = await fetch(url, config); if (!response.ok) { const error: ApiError = await response.json(); throw new Error(error.message || 'An error occurred'); } return response.json(); } catch (error) { // Network error handling if (error instanceof TypeError) { throw new Error('Network connection issue'); } throw error; } } // Types for entities interface Product { id: string; name: string; price: number; description: string; imageUrl: string; } // Products service export const productApi = { // Get all products getAll: () => request('/products'), // Get product by ID getById: (id: string) => request(`/products/${id}`), // Create a product create: (data: Omit) => request('/products', { method: 'POST', body: JSON.stringify(data), }), // Update a product update: (id: string, data: Partial) => request(`/products/${id}`, { method: 'PATCH', body: JSON.stringify(data), }), }; ``` ```tsx // hooks/useProducts.ts import { useState, useEffect, useCallback } from 'react'; import { productApi } from '../services/api'; interface Product { id: string; name: string; price: number; description: string; imageUrl: string; } // Custom hook for product management export function useProducts() { const [products, setProducts] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); // Initial products loading const fetchProducts = useCallback(async () => { setIsLoading(true); setError(null); try { const data = await productApi.getAll(); setProducts(data); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); } finally { setIsLoading(false); } }, []); // Refresh (pull-to-refresh) const refresh = useCallback(async () => { await fetchProducts(); }, [fetchProducts]); // Load on mount useEffect(() => { fetchProducts(); }, [fetchProducts]); return { products, isLoading, error, refresh, }; } ``` ```tsx // screens/ProductListScreen.tsx import React from 'react'; import { View, Text, FlatList, Image, StyleSheet, RefreshControl, ActivityIndicator, } from 'react-native'; import { useProducts } from '../hooks/useProducts'; export function ProductListScreen() { const { products, isLoading, error, refresh } = useProducts(); // Display during initial loading if (isLoading && products.length === 0) { return ( Loading... ); } // Display on error if (error) { return ( {error} ); } return ( item.id} contentContainerStyle={styles.list} // Pull-to-refresh refreshControl={ } renderItem={({ item }) => ( {item.name} ${item.price.toFixed(2)} )} /> ); } const styles = StyleSheet.create({ centered: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20, }, loadingText: { marginTop: 12, fontSize: 16, color: '#666666', }, errorText: { fontSize: 16, color: '#FF3B30', textAlign: 'center', }, list: { padding: 16, }, card: { backgroundColor: '#ffffff', borderRadius: 12, marginBottom: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3, }, image: { width: '100%', height: 200, borderTopLeftRadius: 12, borderTopRightRadius: 12, }, cardContent: { padding: 16, }, productName: { fontSize: 18, fontWeight: '600', color: '#1a1a1a', marginBottom: 4, }, productPrice: { fontSize: 16, color: '#007AFF', fontWeight: '500', }, }); ``` ## Local Data Storage Lokaler Speicher ermöglicht es, Daten zwischen Sitzungen zu persistieren. AsyncStorage ist die Standardlösung für einfache Daten, während SQLite sich für komplexe strukturierte Daten eignet. ```tsx // services/storage.ts import AsyncStorage from '@react-native-async-storage/async-storage'; // Required installation: npx expo install @react-native-async-storage/async-storage // Centralized storage keys const STORAGE_KEYS = { USER_TOKEN: '@app/user_token', USER_PREFERENCES: '@app/user_preferences', ONBOARDING_COMPLETE: '@app/onboarding_complete', } as const; // Types for user preferences interface UserPreferences { theme: 'light' | 'dark' | 'system'; notifications: boolean; language: string; } // Typed storage service export const storage = { // Authentication token async getToken(): Promise { return AsyncStorage.getItem(STORAGE_KEYS.USER_TOKEN); }, async setToken(token: string): Promise { await AsyncStorage.setItem(STORAGE_KEYS.USER_TOKEN, token); }, async removeToken(): Promise { await AsyncStorage.removeItem(STORAGE_KEYS.USER_TOKEN); }, // User preferences (JSON object) async getPreferences(): Promise { const data = await AsyncStorage.getItem(STORAGE_KEYS.USER_PREFERENCES); return data ? JSON.parse(data) : null; }, async setPreferences(prefs: UserPreferences): Promise { await AsyncStorage.setItem( STORAGE_KEYS.USER_PREFERENCES, JSON.stringify(prefs) ); }, // Onboarding async isOnboardingComplete(): Promise { const value = await AsyncStorage.getItem(STORAGE_KEYS.ONBOARDING_COMPLETE); return value === 'true'; }, async setOnboardingComplete(): Promise { await AsyncStorage.setItem(STORAGE_KEYS.ONBOARDING_COMPLETE, 'true'); }, // Complete cleanup async clearAll(): Promise { const keys = Object.values(STORAGE_KEYS); await AsyncStorage.multiRemove(keys); }, }; ``` > **Schutz sensibler Daten** > > Für sensible Daten wie Authentifizierungstoken sollte expo-secure-store eingesetzt werden. Dieses Paket verschlüsselt die Daten über iOS Keychain und Android Keystore. ## Responsive Styles and Theming Eine professionelle App muss sich an verschiedene Bildschirmgrössen anpassen und den Dark Mode unterstützen. ```tsx // theme/index.ts import { Dimensions, PixelRatio, Platform } from 'react-native'; const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window'); // Reference dimensions (iPhone 14) const guidelineBaseWidth = 390; const guidelineBaseHeight = 844; // Scaling functions export const scale = (size: number) => (SCREEN_WIDTH / guidelineBaseWidth) * size; export const verticalScale = (size: number) => (SCREEN_HEIGHT / guidelineBaseHeight) * size; export const moderateScale = (size: number, factor = 0.5) => size + (scale(size) - size) * factor; // Light theme export const lightTheme = { colors: { primary: '#007AFF', secondary: '#5856D6', success: '#34C759', warning: '#FF9500', error: '#FF3B30', background: '#FFFFFF', surface: '#F2F2F7', text: '#000000', textSecondary: '#8E8E93', border: '#E5E5EA', }, spacing: { xs: scale(4), sm: scale(8), md: scale(16), lg: scale(24), xl: scale(32), }, typography: { h1: { fontSize: moderateScale(32), fontWeight: 'bold' as const, lineHeight: moderateScale(40), }, h2: { fontSize: moderateScale(24), fontWeight: 'bold' as const, lineHeight: moderateScale(32), }, body: { fontSize: moderateScale(16), lineHeight: moderateScale(24), }, caption: { fontSize: moderateScale(14), lineHeight: moderateScale(20), }, }, borderRadius: { sm: scale(4), md: scale(8), lg: scale(12), full: 9999, }, }; // Dark theme export const darkTheme = { ...lightTheme, colors: { ...lightTheme.colors, background: '#000000', surface: '#1C1C1E', text: '#FFFFFF', textSecondary: '#8E8E93', border: '#38383A', }, }; export type Theme = typeof lightTheme; ``` ```tsx // context/ThemeContext.tsx import React, { createContext, useContext, useState, useEffect } from 'react'; import { useColorScheme } from 'react-native'; import { lightTheme, darkTheme, Theme } from '../theme'; import { storage } from '../services/storage'; interface ThemeContextType { theme: Theme; isDark: boolean; toggleTheme: () => void; setThemeMode: (mode: 'light' | 'dark' | 'system') => void; } const ThemeContext = createContext(undefined); export function ThemeProvider({ children }: { children: React.ReactNode }) { const systemColorScheme = useColorScheme(); const [themeMode, setThemeMode] = useState<'light' | 'dark' | 'system'>('system'); // Determine effective theme const isDark = themeMode === 'system' ? systemColorScheme === 'dark' : themeMode === 'dark'; const theme = isDark ? darkTheme : lightTheme; // Load preferences on startup useEffect(() => { storage.getPreferences().then((prefs) => { if (prefs?.theme) { setThemeMode(prefs.theme); } }); }, []); // Toggle between light and dark const toggleTheme = () => { const newMode = isDark ? 'light' : 'dark'; setThemeMode(newMode); storage.getPreferences().then((prefs) => { storage.setPreferences({ ...prefs, theme: newMode, notifications: prefs?.notifications ?? true, language: prefs?.language ?? 'en', }); }); }; return ( {children} ); } export function useTheme() { const context = useContext(ThemeContext); if (!context) { throw new Error('useTheme must be used within a ThemeProvider'); } return context; } ``` ## Preparing for Publication Vor der Veröffentlichung einer App sind mehrere Konfigurations- und Optimierungsschritte notwendig. ```json // app.json { "expo": { "name": "MyApp", "slug": "my-app", "version": "1.0.0", "orientation": "portrait", "icon": "./assets/icon.png", "userInterfaceStyle": "automatic", "splash": { "image": "./assets/splash.png", "resizeMode": "contain", "backgroundColor": "#007AFF" }, "ios": { "supportsTablet": true, "bundleIdentifier": "com.example.myapp", "buildNumber": "1" }, "android": { "adaptiveIcon": { "foregroundImage": "./assets/adaptive-icon.png", "backgroundColor": "#007AFF" }, "package": "com.example.myapp", "versionCode": 1 }, "plugins": [ "expo-router" ] } } ``` ```bash # build.sh # EAS Build configuration (Expo Application Services) npm install -g eas-cli # Log in to Expo account eas login # Configure the project eas build:configure # Build for iOS (simulator) eas build --platform ios --profile development # Build for Android (test APK) eas build --platform android --profile preview # Production build eas build --platform all --profile production # Store submission eas submit --platform ios eas submit --platform android ``` > **Zertifikate und Schlüssel** > > Für die iOS-Veröffentlichung wird ein Apple Developer Account (99 $/Jahr) benötigt, für Android ein Google Play Console-Konto (einmalig 25 $). EAS verwaltet Signaturzertifikate automatisch. ## Conclusion React Native bietet einen effizienten Ansatz für die Entwicklung plattformübergreifender Mobile Apps. Die in diesem Leitfaden behandelten Grundlagen ermöglichen es, vollständige und professionelle Anwendungen zu erstellen. ### Checkliste für eine erfolgreiche React-Native-App - Die Entwicklungsumgebung mit Expo für einen schnellen Start einrichten - Kernkomponenten beherrschen: View, Text, TouchableOpacity, FlatList - Navigation mit React Navigation und TypeScript-Typisierung implementieren - State mit der Context API und Custom Hooks verwalten - API-Aufrufe mit einer dedizierten Service-Schicht strukturieren - Daten lokal mit AsyncStorage persistieren - Ein responsives Theme-System mit Dark-Mode-Unterstützung erstellen Die offizielle Dokumentation von React Native und Expo bleibt die Referenz, um jedes Thema zu vertiefen. Das Ökosystem entwickelt sich rasant weiter, und Bibliotheken wie React Query oder Zustand können das Datenmanagement in komplexeren Anwendungen zusätzlich vereinfachen. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/de/blog/react-native/react-native-building-complete-mobile-app