Dezember 21, 2025
17 Min. Lesezeit

React Native Senior Interviewfragen mit Antworten

interview
career-advice
job-search
React Native Senior Interviewfragen mit Antworten
Milad Bonakdar

Milad Bonakdar

Autor

Bereite dich auf Senior-React-Native-Interviews vor: Architektur, FlatList-Performance, native Module, State Management, Testing und produktionsnahe Trade-offs.


Einführung

In Senior-React-Native-Interviews geht es selten nur um Syntax. Rechne mit Fragen zu App-Architektur, Performance-Profiling, nativer Integration, State- und Datengrenzen, Teststrategie, Release-Qualität und dazu, wie du Trade-offs unter echten Produktbedingungen erklärst.

Nutze diesen Leitfaden, um klare Senior-Antworten zu üben. Starte mit der Entscheidung, die du treffen würdest, und erkläre dann Begründung, Risiko und Fallback. Sage bei FlatList zum Beispiel nicht nur, dass man optimieren kann; erkläre, wie du leere Bereiche, Rendering-Batches, memoisiert Rows, stabile Keys und Designänderungen bei festen Item-Höhen oder schweren Bildern prüfen würdest.


Fortgeschrittenes React & Hooks (5 Fragen)

1. Erkläre useMemo und useCallback. Wann solltest du sie verwenden?

Antwort: Beide Hooks optimieren die Leistung, indem sie Werte/Funktionen memoizieren.

  • useMemo: Memoisiert berechnete Werte (teure Berechnungen)
  • useCallback: Memoisiert Funktionsreferenzen (verhindert Neuerstellung)
  • Wann verwenden: Nur wenn Leistungsprobleme auftreten. Vorzeitige Optimierung kann den Code schwerer lesbar machen.
import { useMemo, useCallback, useState } from 'react';

function ExpensiveComponent({ items, onItemClick }) {
  // useMemo - memoisiert teure Berechnungen
  const sortedItems = useMemo(() => {
    console.log('Sortiere Elemente...');
    return items.sort((a, b) => a.price - b.price);
  }, [items]); // Nur neu berechnen, wenn sich Elemente ändern
  
  // useCallback - memoisiert Funktion
  const handleClick = useCallback((id) => {
    console.log('Element geklickt:', id);
    onItemClick(id);
  }, [onItemClick]); // Nur neu erstellen, wenn sich onItemClick ändert
  
  return (
    <FlatList
      data={sortedItems}
      renderItem={({ item }) => (
        <ItemRow item={item} onClick={handleClick} />
      )}
    />
  );
}

// Kindkomponente mit React.memo
const ItemRow = React.memo(({ item, onClick }) => {
  console.log('Rendere Element:', item.id);
  return (
    <TouchableOpacity onPress={() => onClick(item.id)}>
      <Text>{item.name}</Text>
    </TouchableOpacity>
  );
});

Seltenheit: Sehr häufig Schwierigkeit: Mittel


2. Was ist useRef und was sind seine Anwendungsfälle?

Antwort: useRef erstellt eine mutable Referenz, die über Renderings hinweg erhalten bleibt, ohne Re-Renderings auszulösen.

  • Anwendungsfälle:
    • Zugriff auf DOM-/native Elemente
    • Speichern von mutablen Werten, ohne Re-Rendering auszulösen
    • Speichern vorheriger Werte
    • Speichern von Timern/Intervallen
import { useRef, useEffect } from 'react';
import { TextInput, Animated } from 'react-native';

function FormComponent() {
  const inputRef = useRef(null);
  const previousValue = useRef('');
  const animatedValue = useRef(new Animated.Value(0)).current;
  
  useEffect(() => {
    // Fokussiere Eingabe beim Mounten
    inputRef.current?.focus();
  }, []);
  
  const handleChange = (text) => {
    console.log('Vorheriger:', previousValue.current);
    console.log('Aktuell:', text);
    previousValue.current = text;
  };
  
  const startAnimation = () => {
    Animated.timing(animatedValue, {
      toValue: 1,
      duration: 300,
      useNativeDriver: true,
    }).start();
  };
  
  return (
    <View>
      <TextInput ref={inputRef} onChangeText={handleChange} />
      <Animated.View style={{ opacity: animatedValue }}>
        <Text>Animierter Inhalt</Text>
      </Animated.View>
    </View>
  );
}

// Timer-Beispiel
function Timer() {
  const intervalRef = useRef(null);
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    intervalRef.current = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
    
    return () => clearInterval(intervalRef.current);
  }, []);
  
  return <Text>{count}</Text>;
}

Seltenheit: Häufig Schwierigkeit: Mittel


3. Erkläre Custom Hooks und wann man sie erstellen sollte.

Antwort: Custom Hooks extrahieren wiederverwendbare zustandsbehaftete Logik in separate Funktionen.

  • Vorteile: Code-Wiederverwendung, Trennung von Belangen, einfacheres Testen
  • Konvention: Muss mit "use" beginnen
// Custom Hook für API-Fetching
function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        const json = await response.json();
        setData(json);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };
    
    fetchData();
  }, [url]);
  
  return { data, loading, error };
}

// Custom Hook für Formularverarbeitung
function useForm(initialValues) {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});
  
  const handleChange = (name, value) => {
    setValues(prev => ({ ...prev, [name]: value }));
  };
  
  const validate = (validationRules) => {
    const newErrors = {};
    Object.keys(validationRules).forEach(field => {
      const rule = validationRules[field];
      if (rule.required && !values[field]) {
        newErrors[field] = `${field} ist erforderlich`;
      }
    });
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };
  
  return { values, errors, handleChange, validate };
}

// Verwendung
function UserProfile() {
  const { data, loading, error } = useFetch('https://api.example.com/user');
  const { values, errors, handleChange, validate } = useForm({
    name: '',
    email: '',
  });
  
  if (loading) return <ActivityIndicator />;
  if (error) return <Text>Error: {error}</Text>;
  
  return <Text>{data.name}</Text>;
}

Seltenheit: Häufig Schwierigkeit: Mittel


4. Was ist React Context und wann solltest du es verwenden?

Antwort: Context bietet eine Möglichkeit, Daten durch den Komponentenbaum zu übergeben, ohne Prop-Drilling.

  • Anwendungsfälle: Theme, Authentifizierung, Spracheinstellungen
  • Vorsicht: Kann unnötige Re-Renderings verursachen, wenn nicht sorgfältig verwendet
import { createContext, useContext, useState } from 'react';

// Erstelle Context
const ThemeContext = createContext();
const AuthContext = createContext();

// Theme Provider
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  
  const toggleTheme = () => {
    setTheme(prev => prev === 'light' ? 'dark' : 'light');
  };
  
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// Auth Provider
function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  
  const login = async (credentials) => {
    const user = await loginAPI(credentials);
    setUser(user);
  };
  
  const logout = () => {
    setUser(null);
  };
  
  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

// Custom Hooks für Context
function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme muss innerhalb von ThemeProvider verwendet werden');
  }
  return context;
}

function useAuth() {
  return useContext(AuthContext);
}

// Verwendung
function App() {
  return (
    <ThemeProvider>
      <AuthProvider>
        <MainApp />
      </AuthProvider>
    </ThemeProvider>
  );
}

function ThemedButton() {
  const { theme, toggleTheme } = useTheme();
  const { user } = useAuth();
  
  return (
    <TouchableOpacity
      style={{ backgroundColor: theme === 'light' ? '#fff' : '#333' }}
      onPress={toggleTheme}
    >
      <Text>{user ? `Hallo, ${user.name}` : 'Gast'}</Text>
    </TouchableOpacity>
  );
}

Seltenheit: Sehr häufig Schwierigkeit: Mittel


5. Erkläre den Unterschied zwischen useEffect und useLayoutEffect.

Antwort: Beide führen Side Effects aus, aber zu unterschiedlichen Zeiten:

  • useEffect: Wird asynchron ausgeführt, nachdem das Rendering auf dem Bildschirm gezeichnet wurde
  • useLayoutEffect: Wird synchron vor dem Zeichnen ausgeführt (blockiert visuelle Updates)
  • Verwende useLayoutEffect wann: Du musst das DOM messen oder visuelles Flimmern verhindern
import { useEffect, useLayoutEffect, useRef, useState } from 'react';

function MeasureComponent() {
  const [height, setHeight] = useState(0);
  const elementRef = useRef(null);
  
  // useLayoutEffect - messen vor dem Zeichnen
  useLayoutEffect(() => {
    if (elementRef.current) {
      const { height } = elementRef.current.measure((x, y, width, height) => {
        setHeight(height);
      });
    }
  }, []);
  
  // useEffect - nach dem Zeichnen
  useEffect(() => {
    console.log('Komponente gerendert');
  }, []);
  
  return (
    <View ref={elementRef}>
      <Text>Höhe: {height}</Text>
    </View>
  );
}

Seltenheit: Mittel Schwierigkeit: Schwer


State Management (4 Fragen)

6. Erkläre Redux und seine Kernprinzipien.

Antwort: Redux ist ein vorhersehbarer State-Container für JavaScript-Apps.

Loading diagram...
  • Kernprinzipien:
    • Single Source of Truth (ein Store)
    • State ist schreibgeschützt (Aktionen zum Ändern dispatch)
    • Änderungen werden mit reinen Funktionen vorgenommen (Reduzierer)
// Aktionstypen
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';

// Aktions-Ersteller
const addTodo = (text) => ({
  type: ADD_TODO,
  payload: { id: Date.now(), text, completed: false },
});

const toggleTodo = (id) => ({
  type: TOGGLE_TODO,
  payload: id,
});

// Reduzierer
const todosReducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [...state, action.payload];
    case TOGGLE_TODO:
      return state.map(todo =>
        todo.id === action.payload
          ? { ...todo, completed: !todo.completed }
          : todo
      );
    default:
      return state;
  }
};

// Store
import { createStore } from 'redux';
const store = createStore(todosReducer);

// React Native Komponente
import { useSelector, useDispatch } from 'react-redux';

function TodoList() {
  const todos = useSelector(state => state.todos);
  const dispatch = useDispatch();
  
  return (
    <View>
      <FlatList
        data={todos}
        renderItem={({ item }) => (
          <TouchableOpacity onPress={() => dispatch(toggleTodo(item.id))}>
            <Text style={{ textDecorationLine: item.completed ? 'line-through' : 'none' }}>
              {item.text}
            </Text>
          </TouchableOpacity>
        )}
      />
      <Button title="Hinzufügen" onPress={() => dispatch(addTodo('Neue Aufgabe'))} />
    </View>
  );
}

Seltenheit: Sehr häufig Schwierigkeit: Schwer


7. Was ist Redux Toolkit und wie vereinfacht es Redux?

Antwort: Redux Toolkit ist die offiziell empfohlene Methode, um Redux-Logik zu schreiben.

  • Vorteile:
    • Weniger Boilerplate
    • Eingebautes Immer für immutable Updates
    • Enthält Redux Thunk
    • Bessere TypeScript-Unterstützung
import { createSlice, configureStore } from '@reduxjs/toolkit';

// Slice (kombiniert Aktionen und Reduzierer)
const todosSlice = createSlice({
  name: 'todos',
  initialState: [],
  reducers: {
    addTodo: (state, action) => {
      // Immer erlaubt "mutierenden" Code
      state.push({
        id: Date.now(),
        text: action.payload,
        completed: false,
      });
    },
    toggleTodo: (state, action) => {
      const todo = state.find(t => t.id === action.payload);
      if (todo) {
        todo.completed = !todo.completed;
      }
    },
  },
});

export const { addTodo, toggleTodo } = todosSlice.actions;

// Store
const store = configureStore({
  reducer: {
    todos: todosSlice.reducer,
  },
});

// Async Thunk
import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchTodos = createAsyncThunk(
  'todos/fetchTodos',
  async () => {
    const response = await fetch('https://api.example.com/todos');
    return response.json();
  }
);

const todosSlice = createSlice({
  name: 'todos',
  initialState: { items: [], loading: false, error: null },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchTodos.pending, (state) => {
        state.loading = true;
      })
      .addCase(fetchTodos.fulfilled, (state, action) => {
        state.loading = false;
        state.items = action.payload;
      })
      .addCase(fetchTodos.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message;
      });
  },
});

Seltenheit: Häufig Schwierigkeit: Mittel


8. Was sind Alternativen zu Redux für State Management?

Antwort: Es gibt mehrere State-Management-Lösungen:

  • Context API + useReducer: Eingebaut, gut für einfache Apps
  • MobX: Observable-basiert, weniger Boilerplate
  • Zustand: Minimal, Hooks-basiert
  • Recoil: Atom-basiert, von Facebook
  • Jotai: Primitive Atome
// Zustand Beispiel
import create from 'zustand';

const useStore = create((set) => ({
  todos: [],
  addTodo: (text) => set((state) => ({
    todos: [...state.todos, { id: Date.now(), text, completed: false }],
  })),
  toggleTodo: (id) => set((state) => ({
    todos: state.todos.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    ),
  })),
}));

// Verwendung
function TodoList() {
  const { todos, addTodo, toggleTodo } = useStore();
  
  return (
    <View>
      <FlatList
        data={todos}
        renderItem={({ item }) => (
          <TouchableOpacity onPress={() => toggleTodo(item.id)}>
            <Text>{item.text}</Text>
          </TouchableOpacity>
        )}
      />
    </View>
  );
}

Seltenheit: Häufig Schwierigkeit: Mittel


9. Wie handhabst du Side Effects in Redux?

Antwort: Verwende Middleware für asynchrone Operationen:

  • Redux Thunk: Funktionen, die Funktionen zurückgeben
  • Redux Saga: Generator-basiert, leistungsfähiger
  • Redux Observable: RxJS-basiert
// Redux Thunk
const fetchUser = (userId) => async (dispatch) => {
  dispatch({ type: 'FETCH_USER_REQUEST' });
  
  try {
    const response = await fetch(`https://api.example.com/users/${userId}`);
    const user = await response.json();
    dispatch({ type: 'FETCH_USER_SUCCESS', payload: user });
  } catch (error) {
    dispatch({ type: 'FETCH_USER_FAILURE', payload: error.message });
  }
};

// Verwendung
dispatch(fetchUser(123));

// Redux Saga
import { call, put, takeEvery } from 'redux-saga/effects';

function* fetchUserSaga(action) {
  try {
    const user = yield call(fetch, `https://api.example.com/users/${action.payload}`);
    const data = yield call([user, 'json']);
    yield put({ type: 'FETCH_USER_SUCCESS', payload: data });
  } catch (error) {
    yield put({ type: 'FETCH_USER_FAILURE', payload: error.message });
  }
}

function* watchFetchUser() {
  yield takeEvery('FETCH_USER_REQUEST', fetchUserSaga);
}

Seltenheit: Häufig Schwierigkeit: Schwer


Leistungsoptimierung (5 Fragen)

10. Wie optimierst du die Leistung von FlatList?

Antwort: Mehrere Strategien verbessern das Scrollen von FlatList, aber eine Senior-Antwort beginnt mit dem Profiling des Symptoms: leere Bereiche, langsame Taps, Speicherdruck, teure Row-Renderings oder Netzwerk-Pagination. Optimiere die Liste erst, wenn klar ist, welches Problem du löst.

  1. Verwende keyExtractor: Stelle stabile eindeutige Schlüssel bereit
  2. getItemLayout: Überspringe Messungen, wenn Höhe oder Breite der Items vorhersehbar ist
  3. Tune Render-Batches: Balanciere initialNumToRender, maxToRenderPerBatch, updateCellsBatchingPeriod und windowSize
  4. Halte Rows leicht: Verschiebe schwere Logik aus Row-Komponenten und skaliere oder cache Bilder
  5. Memoisiere Row-Komponenten und renderItem: Nutze React.memo und useCallback, wenn Prop-Referenzen stabil sind
  6. Nutze Pagination bewusst: Vermeide blockierende Interaktionen beim Anhängen neuer Daten
  7. Validiere auf echten Geräten: Simulatoren können Speicher- und Scroll-Probleme verbergen
import React, { memo, useCallback } from 'react';

const ITEM_HEIGHT = 80;

// Memoized Item-Komponente
const ListItem = memo(({ item, onPress }) => {
  return (
    <TouchableOpacity onPress={() => onPress(item.id)} style={{ height: ITEM_HEIGHT }}>
      <Text>{item.name}</Text>
    </TouchableOpacity>
  );
});

function OptimizedList({ data }) {
  const handlePress = useCallback((id) => {
    console.log('Gedrückt:', id);
  }, []);
  
  const renderItem = useCallback(({ item }) => (
    <ListItem item={item} onPress={handlePress} />
  ), [handlePress]);
  
  const keyExtractor = useCallback((item) => item.id.toString(), []);
  
  const getItemLayout = useCallback((data, index) => ({
    length: ITEM_HEIGHT,
    offset: ITEM_HEIGHT * index,
    index,
  }), []);
  
  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      getItemLayout={getItemLayout}
      removeClippedSubviews={true}
      maxToRenderPerBatch={10}
      updateCellsBatchingPeriod={50}
      initialNumToRender={10}
      windowSize={5}
    />
  );
}

Seltenheit: Sehr häufig Schwierigkeit: Mittel


11. Was ist die React Native Bridge und wie beeinflusst sie die Leistung?

Antwort: Die Legacy-Bridge ist die Kommunikationsschicht zwischen JavaScript und nativem Code. Ältere React-Native-Apps senden serialisierte asynchrone Nachrichten über diese Grenze, sodass häufige JavaScript/native Kommunikation Animationen, Scrolling und Startarbeit belasten kann.

  • Funktionsweise in der Legacy-Architektur:
    • JavaScript läuft getrennt von nativer UI und Plattformcode
    • Native Module laufen auf nativen Threads
    • Daten über die Bridge müssen serialisiert werden
  • Leistungsauswirkungen:
    • Viele kleine Aufrufe können zum Engpass werden
    • Große Payloads verursachen Serialisierungskosten
    • UI-Arbeit kann verzögert wirken, wenn JS ausgelastet ist
  • Senior-Mitigation:
    • Bridge-Übergänge reduzieren und native Arbeit bündeln
    • Native-driven Animationen oder Reanimated für gesture-lastige Flows nutzen
    • Vor dem Umschreiben profilieren
    • Bei neueren Apps verstehen, wie JSI, Fabric und TurboModules Bridge-Grenzen reduzieren, aber Library-Kompatibilität weiter geprüft werden muss
// Schlecht - häufige Bridge-Übergänge
const BadAnimation = () => {
  const [position, setPosition] = useState(0);
  
  useEffect(() => {
    const interval = setInterval(() => {
      setPosition(p => p + 1); // Bridge-Übergang bei jedem Frame!
    }, 16);
    return () => clearInterval(interval);
  }, []);
  
  return <View style={{ transform: [{ translateX: position }] }} />;
};

// Gut - native Animation (keine Bridge)
const GoodAnimation = () => {
  const translateX = useRef(new Animated.Value(0)).current;
  
  useEffect(() => {
    Animated.timing(translateX, {
      toValue: 100,
      duration: 1000,
      useNativeDriver: true, // Läuft im nativen Thread!
    }).start();
  }, []);
  
  return <Animated.View style={{ transform: [{ translateX }] }} />;
};

Seltenheit: Häufig Schwierigkeit: Schwer


12. Wie verhinderst du unnötige Re-Renderings?

Antwort: Mehrere Techniken verhindern unnötige Renderings:

  1. React.memo: Memoisiere Komponenten
  2. useMemo/useCallback: Memoisiere Werte/Funktionen
  3. Korrekte Key-Props: Helfen React, Änderungen zu identifizieren
  4. Vermeide Inline-Objekte/Arrays: Erstelle neue Referenzen
  5. Teile Komponenten auf: Kleinere, fokussierte Komponenten
// Schlecht - erstellt bei jedem Rendering ein neues Objekt
function BadComponent() {
  return <ChildComponent style={{ margin: 10 }} />; // Neues Objekt!
}

// Gut - stabile Referenz
const styles = StyleSheet.create({
  container: { margin: 10 },
});

function GoodComponent() {
  return <ChildComponent style={styles.container} />;
}

// React.memo mit benutzerdefiniertem Vergleich
const ExpensiveComponent = React.memo(
  ({ data, onPress }) => {
    console.log('Rendere ExpensiveComponent');
    return (
      <View>
        <Text>{data.name}</Text>
        <Button onPress={onPress} />
      </View>
    );
  },
  (prevProps, nextProps) => {
    // Benutzerdefinierter Vergleich - nur Re-Rendering, wenn sich data.id geändert hat
    return prevProps.data.id === nextProps.data.id;
  }
);

// Teile Komponenten auf, um Re-Renderings zu isolieren
function ParentComponent() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');
  
  return (
    <View>
      {/* Nur Re-Rendering, wenn sich count ändert */}
      <CountDisplay count={count} />
      
      {/* Nur Re-Rendering, wenn sich text ändert */}
      <TextDisplay text={text} />
      
      <Button onPress={() => setCount(c => c + 1)} />
    </View>
  );
}

const CountDisplay = React.memo(({ count }) => <Text>{count}</Text>);
const TextDisplay = React.memo(({ text }) => <Text>{text}</Text>);

Seltenheit: Sehr häufig Schwierigkeit: Mittel


13. Wie optimierst du Bilder in React Native?

Antwort: Bildoptimierung ist entscheidend für die Leistung:

  1. Größe von Bildern ändern: Verwende geeignete Abmessungen
  2. Bilder zwischenspeichern: Verwende Bibliotheken wie react-native-fast-image
  3. Lazy Loading: Lade Bilder bei Bedarf
  4. Progressives Laden: Zeige zuerst einen Platzhalter
  5. Verwende das WebP-Format: Bessere Komprimierung
import FastImage from 'react-native-fast-image';

function OptimizedImage({ uri }) {
  return (
    <FastImage
      source={{
        uri,
        priority: FastImage.priority.normal,
        cache: FastImage.cacheControl.immutable,
      }}
      resizeMode={FastImage.resizeMode.cover}
      style={{ width: 200, height: 200 }}
    />
  );
}

// Progressives Laden von Bildern
function ProgressiveImage({ thumbnailUri, fullUri }) {
  const [imageLoaded, setImageLoaded] = useState(false);
  
  return (
    <View>
      <Image
        source={{ uri: thumbnailUri }}
        style={styles.image}
        blurRadius={imageLoaded ? 0 : 5}
      />
      <Image
        source={{ uri: fullUri }}
        style={[styles.image, { opacity: imageLoaded ? 1 : 0 }]}
        onLoad={() => setImageLoaded(true)}
      />
    </View>
  );
}

// Image Prefetching
import { Image } from 'react-native';

const prefetchImages = async (urls) => {
  const promises = urls.map(url => Image.prefetch(url));
  await Promise.all(promises);
};

Seltenheit: Häufig Schwierigkeit: Mittel


14. Welche Tools verwendest du für das Performance-Profiling?

Antwort: Mehrere Tools helfen, Leistungsprobleme zu identifizieren:

  • React DevTools Profiler: Renderzeiten von Komponenten
  • Flipper: Debugging- und Profiling-Tool
  • Performance Monitor: Eingebauter FPS-Monitor
  • Systrace: Android Performance Tracing
  • Instruments: iOS Performance Profiling
// Aktiviere den Performance-Monitor im Dev-Modus
import { LogBox } from 'react-native';

if (__DEV__) {
  // Zeige den Performance-Monitor an
  require('react-native').unstable_enableLogBox();
}

// Messe die Renderzeit von Komponenten
import { Profiler } from 'react';

function onRenderCallback(
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  commitTime
) {
  console.log(`${id} (${phase}) dauerte ${actualDuration}ms`);
}

function App() {
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <MyComponent />
    </Profiler>
  );
}

// Benutzerdefinierte Performance-Tracking
const measurePerformance = (name, fn) => {
  const start = performance.now();
  const result = fn();
  const end = performance.now();
  console.log(`${name} dauerte ${end - start}ms`);
  return result;
};

Seltenheit: Häufig Schwierigkeit: Mittel


Native Module & Plattformspezifisch (4 Fragen)

15. Wie erstellst du ein natives Modul in React Native?

Antwort: Native Module ermöglichen die Verwendung von plattformspezifischem Code.

// iOS (Objective-C) - CalendarManager.m
#import "CalendarManager.h"
#import <React/RCTLog.h>

@implementation CalendarManager

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
{
  RCTLogInfo(@"Creating event %@ at %@", name, location);
}

@end

// Android (Java) - CalendarModule.java
package com.myapp;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

public class CalendarModule extends ReactContextBaseJavaModule {
  CalendarModule(ReactApplicationContext context) {
    super(context);
  }

  @Override
  public String getName() {
    return "CalendarManager";
  }

  @ReactMethod
  public void addEvent(String name, String location) {
    Log.d("CalendarModule", "Creating event " + name + " at " + location);
  }
}

// JavaScript-Verwendung
import { NativeModules } from 'react-native';

const { CalendarManager } = NativeModules;

function MyComponent() {
  const createEvent = () => {
    CalendarManager.addEvent('Meeting', 'Office');
  };
  
  return <Button title="Event erstellen" onPress={createEvent} />;
}

Seltenheit: Mittel Schwierigkeit: Schwer


16. Wie handhabst du plattformspezifischen Code?

Antwort: Mehrere Ansätze für plattformspezifischen Code:

  1. Plattformmodul: Überprüfe die Plattform zur Laufzeit
  2. Plattformspezifische Dateien: .ios.js und .android.js
  3. Platform.select: Wähle Werte basierend auf der Plattform aus
import { Platform } from 'react-native';

// Plattformmodul
const styles = StyleSheet.create({
  container: {
    paddingTop: Platform.OS === 'ios' ? 20 : 0,
  },
});

// Platform.select
const styles = StyleSheet.create({
  container: {
    ...Platform.select({
      ios: {
        shadowColor: '#000',
        shadowOffset: { width: 0, height: 2 },
        shadowOpacity: 0.3,
      },
      android: {
        elevation: 4,
      },
    }),
  },
});

// Plattformspezifische Dateien
// Button.ios.js
export default function Button() {
  return <Text>iOS Button</Text>;
}

// Button.android.js
export default function Button() {
  return <Text>Android Button</Text>;
}

// Verwendung - wählt automatisch die richtige Datei aus
import Button from './Button';

// Plattformversionsprüfung
if (Platform.Version >= 21) {
  // Android API 21+
}

Seltenheit: Sehr häufig Schwierigkeit: Einfach


17. Was ist die neue Architektur (Fabric und TurboModule)?

Antwort: Die neue Architektur ist das moderne Runtime- und Rendering-Modell von React Native. Sie kombiniert JSI für direkte JavaScript/native Interaktion, Fabric als Renderer und TurboModules für typisierte native Module. Ein Senior-Kandidat sollte Vorteile und Migrationsrisiken erklären.

  • Fabric: Neues Rendering-System
    • Bessere Interoperabilität mit nativen Views
    • Mehr synchrone Layout-Möglichkeiten
    • Für moderne React-Features ausgelegt
  • TurboModules: Neues natives Modulsystem
    • Lazy Loading
    • Typsichere Specs über Codegen
    • Direkte JSI-basierte Kommunikation statt Bridge-Serialisierung

Interview-Framing:

  • Neue Apps sollten die neue Architektur früh evaluieren
  • Bestehende Apps brauchen Dependency-, Build- und Rollout-Checks vor der Migration
  • Performance-Gewinne hängen vom Bottleneck der App ab; keine automatischen Speedups versprechen
  • Ownership nativer Module, CI-Abdeckung und Crash-Monitoring sind genauso wichtig wie ein aktivierter Flag

Seltenheit: Mittel Schwierigkeit: Schwer


18. Wie handhabst du Deep Linking in React Native?

Antwort: Deep Linking ermöglicht das Öffnen bestimmter Bildschirme über URLs.

import { Linking } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';

// Konfiguriere Deep Linking
const linking = {
  prefixes: ['myapp://', 'https://myapp.com'],
  config: {
    screens: {
      Home: 'home',
      Profile: 'profile/:id',
      Settings: 'settings',
    },
  },
};

function App() {
  return (
    <NavigationContainer linking={linking}>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

// Behandle eingehende Links
useEffect(() => {
  const handleUrl = ({ url }) => {
    console.log('Geöffnet mit URL:', url);
    // myapp://profile/123
  };
  
  // App wurde über Link geöffnet
  Linking.getInitialURL().then(url => {
    if (url) handleUrl({ url });
  });
  
  // App bereits geöffnet, neuer Link
  const subscription = Linking.addEventListener('url', handleUrl);
  
  return () => subscription.remove();
}, []);

// Öffne URL programmgesteuert
const openURL = async (url) => {
  const supported = await Linking.canOpenURL(url);
  if (supported) {
    await Linking.openURL(url);
  }
};

Seltenheit: Häufig Schwierigkeit: Mittel


Testen (3 Fragen)

19. Wie testest du React Native-Komponenten?

Antwort: Verwende Testbibliotheken wie Jest und React Native Testing Library.

import { render, fireEvent, waitFor } from '@testing-library/react-native';
import Counter from './Counter';

describe('Counter', () => {
  it('rendert den initialen Zählerwert', () => {
    const { getByText } = render(<Counter />);
    expect(getByText('Zähler: 0')).toBeTruthy();
  });
  
  it('erhöht
Newsletter subscription

Wöchentliche Karrieretipps, die wirklich funktionieren

Erhalten Sie die neuesten Einblicke direkt in Ihr Postfach

Erstellen Sie einen Lebenslauf, der Sie 60% schneller einstellt

Erstellen Sie in wenigen Minuten einen maßgeschneiderten, ATS-freundlichen Lebenslauf, der nachweislich 6-mal mehr Vorstellungsgespräche vermittelt.

Einen besseren Lebenslauf erstellen

Diesen Beitrag teilen

Werden Sie 50% Schneller Eingestellt

Arbeitssuchende mit professionellen, KI-optimierten Lebensläufen finden in durchschnittlich 5 Wochen eine Stelle, verglichen mit den üblichen 10. Hören Sie auf zu warten und beginnen Sie mit Vorstellungsgesprächen.