Toolmingo
Guides25 min read

50 React Native Interview Questions (With Answers)

Top React Native interview questions with detailed answers and code examples — covering architecture, components, navigation, state management, performance, and native modules.

React Native lets you build iOS and Android apps using JavaScript and React. Interviews cover architecture, component lifecycle, navigation, state management, performance, and native integrations. This guide provides 50 common React Native interview questions with detailed answers and code examples.


Table of Contents

  1. Architecture & Core Concepts
  2. Components & Styling
  3. Navigation
  4. State Management
  5. Networking & Data
  6. Performance Optimization
  7. Native Modules & Platform APIs
  8. Expo vs Bare React Native
  9. Testing
  10. Advanced Topics

Architecture & Core Concepts

1. How does React Native work under the hood?

React Native runs JavaScript in a JS engine (Hermes on Android, JavaScriptCore on iOS) and communicates with native components via a bridge (old architecture) or JSI (new architecture).

Old Architecture (Bridge):

  • Async JSON messages cross the bridge between JS thread and native thread
  • Three threads: JS thread, UI thread (main), native modules thread

New Architecture (JSI — JavaScript Interface):

  • Direct C++ references — no serialization overhead
  • Synchronous calls to native modules
  • Fabric renderer replaces the old UIManager
JavaScript Thread (Hermes)
    │
    │  JSI (C++ bindings, synchronous)
    │
Native Threads (UI, background)

2. What is the difference between React Native and React?

Feature React React Native
Target Web browsers iOS & Android
Rendering HTML DOM via ReactDOM Native components via bridge/JSI
Styling CSS classes + styled-components StyleSheet API (subset of CSS)
Navigation React Router React Navigation / Expo Router
Components <div>, <span>, <img> <View>, <Text>, <Image>
Build output HTML/JS/CSS bundle Native binary (.ipa / .apk)
Hot Reload Yes Yes (Fast Refresh)

React Native reuses React's component model and hooks but renders native UI instead of DOM elements.


3. What is JSI (JavaScript Interface) and why is it important?

JSI is a C++ API that allows JavaScript to hold references to native objects directly — without serializing to JSON and crossing an async bridge.

Benefits over the old bridge:

  • Synchronous calls — no async round-trips
  • Type safety — native types exposed to JS directly
  • Performance — eliminates JSON serialization bottleneck
  • TurboModules — lazy-loaded native modules via JSI
  • Fabric — new renderer built on JSI
// Old bridge: async, JSON-serialized
NativeModules.MyModule.doSomething(data, callback);

// JSI / TurboModules: synchronous C++ call
const result = global.__myNativeModule.doSomething(data);

4. What threads does React Native use?

Thread Purpose
JS thread Runs JavaScript (React logic, state, event handlers)
Main/UI thread Renders native views, handles gestures
Native modules thread Async native module calls (network, storage, etc.)
Background threads Image decoding, network I/O (managed by the OS)

The JS thread and UI thread are separate — a slow JS computation won't block scroll animations, but a heavy JS workload can still cause dropped frames if it starves the JS thread.


5. What is Hermes and why does React Native use it?

Hermes is an open-source JavaScript engine optimised for React Native, developed by Meta.

Advantages over JavaScriptCore:

  • Ahead-of-time (AOT) bytecode compilation — faster startup
  • Smaller memory footprint
  • Better performance on low-end Android devices
  • Better source map support for debugging
// android/app/build.gradle
project.ext.react = [
  enableHermes: true  // default in RN 0.70+
]

Hermes is now the default engine for both Android and iOS in React Native 0.70+.


Components & Styling

6. What are the core components in React Native?

Component Purpose Web equivalent
View Container, layout <div>
Text Display text <p>, <span>
Image Display images <img>
TextInput Text entry field <input>
ScrollView Scrollable container <div style="overflow:scroll">
FlatList Virtualized list Virtual scroller
SectionList Grouped list with headers
TouchableOpacity Tappable wrapper with opacity <button>
Pressable Flexible tappable wrapper <button>
Modal Overlay modal Dialog / portal
ActivityIndicator Loading spinner CSS spinner

7. How does styling work in React Native?

React Native uses a StyleSheet API instead of CSS. Styles are JavaScript objects using camelCase properties.

import { StyleSheet, View, Text } from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 16,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#333',
    marginBottom: 8,
  },
});

export default function App() {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Hello React Native</Text>
    </View>
  );
}

Key differences from CSS:

  • No inheritance (except Text inheriting text styles from parent Text)
  • Flexbox is the default layout (column direction by default)
  • No shorthand margin: 8 16 — must use marginVertical/marginHorizontal
  • Numbers (not strings) for fontSize, padding, etc.

8. How does Flexbox work in React Native?

React Native uses Flexbox for layout, but with one key difference: flexDirection defaults to 'column' (not 'row' as in CSS).

const styles = StyleSheet.create({
  row: {
    flexDirection: 'row',        // horizontal
    justifyContent: 'space-between', // main axis
    alignItems: 'center',            // cross axis
  },
  box: {
    flex: 1,          // take equal space
    height: 50,
    backgroundColor: 'tomato',
    marginHorizontal: 4,
  },
});
Property Default in RN Default in CSS
flexDirection 'column' 'row'
alignContent 'flex-start' 'normal'
flexShrink 0 1

9. What is the difference between ScrollView and FlatList?

Feature ScrollView FlatList
Rendering Renders all children at once Virtualised — only renders visible items
Performance Poor with many items Optimised for large datasets
Use case Short content / fixed screens Long lists (contacts, feeds, etc.)
Pull-to-refresh Manual Built-in onRefresh prop
Horizontal scrolling horizontal prop horizontal prop
Separator Manual ItemSeparatorComponent prop
// FlatList — virtualised, efficient for 1000s of items
<FlatList
  data={items}
  keyExtractor={(item) => item.id.toString()}
  renderItem={({ item }) => <ItemCard item={item} />}
  ItemSeparatorComponent={() => <View style={styles.separator} />}
  onRefresh={handleRefresh}
  refreshing={isRefreshing}
/>

10. What is Pressable and how does it differ from TouchableOpacity?

Pressable is the modern, flexible touch handler introduced in React Native 0.63. It replaces TouchableOpacity, TouchableHighlight, and TouchableNativeFeedback.

// TouchableOpacity (older)
<TouchableOpacity onPress={handlePress} activeOpacity={0.7}>
  <Text>Press me</Text>
</TouchableOpacity>

// Pressable (modern, preferred)
<Pressable
  onPress={handlePress}
  onLongPress={handleLongPress}
  style={({ pressed }) => [
    styles.button,
    pressed && styles.buttonPressed,
  ]}
>
  {({ pressed }) => (
    <Text style={pressed ? styles.textPressed : styles.text}>
      {pressed ? 'Pressed!' : 'Press me'}
    </Text>
  )}
</Pressable>

Pressable supports render props with pressed state and hitSlop / delayLongPress without wrapping HOCs.


Navigation

11. What is React Navigation and what are its main navigators?

React Navigation is the standard navigation library for React Native. It provides stack, tab, drawer, and other navigators.

Navigator Use case Component
Stack Push/pop screens (like iOS nav) createNativeStackNavigator
Bottom Tab Tab bar at the bottom createBottomTabNavigator
Material Top Tab Tabs at the top with swipe createMaterialTopTabNavigator
Drawer Sidebar menu createDrawerNavigator
Modal Full-screen overlay Stack with presentation: 'modal'
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator();

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

12. How do you pass data between screens in React Navigation?

// Passing params when navigating
navigation.navigate('Profile', {
  userId: 42,
  name: 'Alice',
});

// Receiving params in destination screen
function ProfileScreen({ route, navigation }) {
  const { userId, name } = route.params;

  return (
    <View>
      <Text>User: {name} (ID: {userId})</Text>
      <Button
        title="Go back"
        onPress={() => navigation.goBack()}
      />
    </View>
  );
}

For complex cross-screen state, prefer a state manager (Zustand, Redux) over params chaining.


13. What is Expo Router and how does it differ from React Navigation?

Expo Router is a file-based routing library (similar to Next.js App Router) built on top of React Navigation.

Feature React Navigation Expo Router
Route definition Imperative code File system (app/ folder)
Deep linking Manual config Automatic
TypeScript routes Manual typing Auto-generated types
Universal React Native only Web + native (universal links)
Setup Manual Built into Expo
app/
  _layout.tsx     ← root layout (NavigationContainer)
  index.tsx       ← "/" or home screen
  profile/
    [id].tsx      ← "/profile/123" with dynamic segment
  (tabs)/
    _layout.tsx   ← tab navigator
    home.tsx
    settings.tsx

14. How do you implement deep linking in React Native?

Deep linking lets URLs open specific screens in your app.

// react-navigation linking config
const linking = {
  prefixes: ['myapp://', 'https://myapp.com'],
  config: {
    screens: {
      Home: '',
      Profile: 'profile/:userId',
      Settings: 'settings',
    },
  },
};

<NavigationContainer linking={linking}>
  {/* navigators */}
</NavigationContainer>

On iOS, configure Associated Domains in Xcode. On Android, add intent filters in AndroidManifest.xml.


State Management

15. What state management options are available in React Native?

Library Best for Key API
useState + useContext Small apps, simple global state React built-ins
Zustand Simple global state, minimal boilerplate create, useStore
Redux Toolkit Large apps, complex state, DevTools configureStore, createSlice
Jotai Atomic state, component-level granularity atom, useAtom
React Query / TanStack Query Server state (cache, sync, loading) useQuery, useMutation
MobX Observable reactive state makeAutoObservable

16. How do you use Zustand in React Native?

import { create } from 'zustand';

// Define store
const useAuthStore = create((set) => ({
  user: null,
  token: null,
  login: (user, token) => set({ user, token }),
  logout: () => set({ user: null, token: null }),
}));

// Use in component
function ProfileScreen() {
  const { user, logout } = useAuthStore();

  return (
    <View>
      <Text>Welcome, {user?.name}</Text>
      <Button title="Logout" onPress={logout} />
    </View>
  );
}

For persistence, combine with zustand/middleware's persist and AsyncStorage.


17. How do you handle async state (loading, error, data) in React Native?

import { useState, useEffect } from 'react';

function useUser(userId) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    let cancelled = false;
    setLoading(true);

    fetchUser(userId)
      .then((data) => {
        if (!cancelled) setUser(data);
      })
      .catch((err) => {
        if (!cancelled) setError(err.message);
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });

    return () => { cancelled = true; }; // cleanup for unmount
  }, [userId]);

  return { user, loading, error };
}

With TanStack Query this is much simpler:

const { data: user, isLoading, error } = useQuery({
  queryKey: ['user', userId],
  queryFn: () => fetchUser(userId),
});

18. What is the Context API and when should you use it over a state library?

// Create context
const ThemeContext = React.createContext('light');

// Provider
function App() {
  const [theme, setTheme] = useState('light');
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <NavigationContainer>
        <RootNavigator />
      </NavigationContainer>
    </ThemeContext.Provider>
  );
}

// Consumer
function ThemedButton() {
  const { theme, setTheme } = useContext(ThemeContext);
  return (
    <Pressable
      style={{ backgroundColor: theme === 'dark' ? '#333' : '#fff' }}
      onPress={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
    >
      <Text>Toggle Theme</Text>
    </Pressable>
  );
}

Use Context when: theme, locale, auth session — infrequently changing, app-wide values.
Use Zustand/Redux when: frequent updates, complex derived state, DevTools needed, or avoiding re-render issues.


Networking & Data

19. How do you make API calls in React Native?

React Native ships with the Fetch API. Use axios for interceptors and timeout support.

// Fetch API
async function getUsers() {
  const response = await fetch('https://api.example.com/users', {
    headers: { Authorization: `Bearer ${token}` },
  });
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  return response.json();
}

// Axios (with base URL + interceptors)
import axios from 'axios';

const api = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000,
});

api.interceptors.request.use((config) => {
  config.headers.Authorization = `Bearer ${getToken()}`;
  return config;
});

const { data: users } = await api.get('/users');

20. How do you store data locally in React Native?

Storage Use case API
AsyncStorage Simple key-value, non-sensitive setItem, getItem, removeItem
SecureStore (Expo) Sensitive data (tokens, passwords) Keychain (iOS) / Keystore (Android)
SQLite (expo-sqlite) Structured relational data SQL queries
MMKV High-performance key-value Synchronous, much faster than AsyncStorage
Realm / WatermelonDB Complex local DB with sync Object-based queries
import AsyncStorage from '@react-native-async-storage/async-storage';

// Save
await AsyncStorage.setItem('user_prefs', JSON.stringify({ theme: 'dark' }));

// Read
const raw = await AsyncStorage.getItem('user_prefs');
const prefs = raw ? JSON.parse(raw) : null;

// Delete
await AsyncStorage.removeItem('user_prefs');

Performance Optimization

21. What causes performance issues in React Native?

Problem Cause Fix
Dropped frames (jank) Heavy JS work on JS thread Move to native thread / worklets
Slow list scrolling Non-virtualised list Use FlatList, not ScrollView
Excessive re-renders Incorrect state structure React.memo, useMemo, useCallback
Large bundle Unused imports Tree shaking, code splitting
Slow image loading Large unoptimised images FastImage, cache headers
JS thread blocked Synchronous heavy computation InteractionManager, Worklets
Bridge congestion Many JS↔native calls Batch calls, use animations on native thread

22. How does React.memo help performance?

// Without memo: re-renders every time parent re-renders
function ExpensiveItem({ item, onPress }) {
  console.log('rendering', item.id);
  return <Pressable onPress={() => onPress(item.id)}><Text>{item.name}</Text></Pressable>;
}

// With memo: only re-renders if props change
const ExpensiveItem = React.memo(function ExpensiveItem({ item, onPress }) {
  return <Pressable onPress={() => onPress(item.id)}><Text>{item.name}</Text></Pressable>;
});

// In parent: stabilise callback with useCallback
function List({ items }) {
  const handlePress = useCallback((id) => {
    console.log('pressed', id);
  }, []); // stable reference

  return (
    <FlatList
      data={items}
      renderItem={({ item }) => (
        <ExpensiveItem item={item} onPress={handlePress} />
      )}
    />
  );
}

23. What is Reanimated and when should you use it?

React Native Reanimated (v2+) allows animations to run on the UI thread using worklets — eliminating bridge overhead.

import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
  withTiming,
} from 'react-native-reanimated';

function AnimatedCard() {
  const scale = useSharedValue(1);
  const opacity = useSharedValue(1);

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

  return (
    <Pressable
      onPressIn={() => { scale.value = withSpring(0.95); }}
      onPressOut={() => { scale.value = withSpring(1); }}
    >
      <Animated.View style={[styles.card, animatedStyle]}>
        <Text>Press me</Text>
      </Animated.View>
    </Pressable>
  );
}

Use Reanimated for: gesture-driven animations, 60fps scroll effects, complex shared element transitions. Use the Animated API for simple one-shot animations.


24. How do you optimise FlatList performance?

<FlatList
  data={items}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <ItemCard item={item} />}

  // Performance props
  removeClippedSubviews={true}        // unmount off-screen views (Android)
  maxToRenderPerBatch={10}            // items rendered per batch
  windowSize={5}                      // render window (x visible heights)
  initialNumToRender={10}             // first render item count
  getItemLayout={(data, index) => ({  // skip measure if fixed height
    length: ITEM_HEIGHT,
    offset: ITEM_HEIGHT * index,
    index,
  })}

  // Interaction
  onEndReached={loadMore}
  onEndReachedThreshold={0.5}
/>

Always define getItemLayout for fixed-height items — it prevents React Native from measuring each item on render.


25. What is InteractionManager and when do you use it?

InteractionManager defers heavy work until after animations complete, preventing jank.

import { InteractionManager } from 'react-native';
import { useEffect } from 'react';

function HeavyScreen() {
  const [data, setData] = useState(null);

  useEffect(() => {
    // Wait for screen transition animation to finish
    const interaction = InteractionManager.runAfterInteractions(() => {
      const result = computeHeavyData(); // runs after animation
      setData(result);
    });

    return () => interaction.cancel();
  }, []);

  return data ? <DataView data={data} /> : <ActivityIndicator />;
}

Native Modules & Platform APIs

26. What are Native Modules and how do you use them?

Native Modules expose platform APIs (Bluetooth, camera, sensors) that don't exist in React Native's JS API.

JavaScript side:

import { NativeModules } from 'react-native';

const { BatteryModule } = NativeModules;

async function checkBattery() {
  const level = await BatteryModule.getBatteryLevel();
  console.log(`Battery: ${Math.round(level * 100)}%`);
}

Android side (Kotlin):

class BatteryModule(reactContext: ReactApplicationContext) :
    ReactContextBaseJavaModule(reactContext) {

    override fun getName() = "BatteryModule"

    @ReactMethod
    fun getBatteryLevel(promise: Promise) {
        val bm = reactContext.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
        val level = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
        promise.resolve(level / 100.0)
    }
}

With the new architecture, use TurboModules and Codegen for type-safe native modules.


27. How do you handle platform-specific code?

import { Platform } from 'react-native';

// Platform.OS check
const styles = StyleSheet.create({
  container: {
    paddingTop: Platform.OS === 'ios' ? 50 : 20,
  },
  shadow: Platform.select({
    ios: {
      shadowColor: '#000',
      shadowOffset: { width: 0, height: 2 },
      shadowOpacity: 0.2,
    },
    android: {
      elevation: 4,
    },
  }),
});

// Platform.Version check
if (Platform.OS === 'android' && Platform.Version < 21) {
  // handle older Android
}

Platform-specific files:

Button.ios.tsx      ← used on iOS
Button.android.tsx  ← used on Android
Button.tsx          ← fallback for web / unknown

28. How do you request permissions in React Native?

Using react-native-permissions (recommended) or Expo's expo-permissions:

import { request, PERMISSIONS, RESULTS } from 'react-native-permissions';

async function requestCamera() {
  const permission = Platform.select({
    ios: PERMISSIONS.IOS.CAMERA,
    android: PERMISSIONS.ANDROID.CAMERA,
  });

  const result = await request(permission);

  switch (result) {
    case RESULTS.GRANTED:
      openCamera();
      break;
    case RESULTS.DENIED:
      Alert.alert('Camera permission denied');
      break;
    case RESULTS.BLOCKED:
      Alert.alert('Open Settings to enable camera access');
      Linking.openSettings();
      break;
  }
}

29. How do you use the camera in React Native?

Using expo-camera (Expo) or react-native-vision-camera (bare, high performance):

import { CameraView, useCameraPermissions } from 'expo-camera';

function CameraScreen() {
  const [permission, requestPermission] = useCameraPermissions();

  if (!permission?.granted) {
    return (
      <View>
        <Text>Camera access needed</Text>
        <Button title="Grant Permission" onPress={requestPermission} />
      </View>
    );
  }

  return (
    <CameraView
      style={StyleSheet.absoluteFill}
      facing="back"
      onBarcodeScanned={({ data }) => console.log('QR:', data)}
    />
  );
}

30. How do you handle push notifications in React Native?

Using Expo Notifications (Expo) or Firebase Cloud Messaging (bare):

import * as Notifications from 'expo-notifications';

// Request permission
const { status } = await Notifications.requestPermissionsAsync();

// Get push token (Expo's managed service)
const token = await Notifications.getExpoPushTokenAsync({
  projectId: Constants.expoConfig.extra.eas.projectId,
});

// Listen for notifications
useEffect(() => {
  const sub = Notifications.addNotificationReceivedListener((notification) => {
    console.log('Received:', notification);
  });

  const tapSub = Notifications.addNotificationResponseReceivedListener((response) => {
    const { screen } = response.notification.request.content.data;
    navigation.navigate(screen);
  });

  return () => { sub.remove(); tapSub.remove(); };
}, []);

Expo vs Bare React Native

31. What is Expo and what are its advantages?

Expo is a framework and platform built on top of React Native that simplifies development.

Feature Expo (Managed) Bare React Native
Setup npx create-expo-app npx @react-native-community/cli init
Native builds EAS Build (cloud) Local Xcode / Android Studio
OTA updates Expo Updates Manual or CodePush
Native modules expo-* modules only Any npm native module
Flexibility Lower (managed) Full control
Xcode/Android Studio required No Yes
File-based routing Expo Router React Navigation (manual)

32. What is EAS (Expo Application Services)?

EAS is Expo's cloud build and submission platform:

  • EAS Build — cloud CI/CD for iOS and Android builds without local Xcode/Android Studio
  • EAS Submit — automated App Store / Google Play submission
  • EAS Update — over-the-air JS bundle updates (without app store review)
# Build for production
eas build --platform all

# Submit to stores
eas submit --platform all

# Push OTA update
eas update --branch production --message "Bug fix"

33. What is the difference between Expo Go and a development build?

Feature Expo Go Development Build
Purpose Quick prototyping Production-like testing
Custom native modules Not supported Fully supported
Build required No Yes (once, via EAS)
Config plugins Limited Full support
App Store distribution No Yes

Use Expo Go for learning and simple projects. Switch to a development build when you need custom native code.


Testing

34. What are the testing levels in React Native?

Level Tool What it tests
Unit Jest Pure functions, utilities, hooks
Component React Native Testing Library Component rendering, interactions
E2E Detox / Maestro Full user flows on real device/emulator

35. How do you write component tests with React Native Testing Library?

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

describe('LoginForm', () => {
  it('shows error when email is empty', () => {
    render(<LoginForm onLogin={jest.fn()} />);

    fireEvent.press(screen.getByRole('button', { name: /login/i }));

    expect(screen.getByText('Email is required')).toBeTruthy();
  });

  it('calls onLogin with credentials', () => {
    const onLogin = jest.fn();
    render(<LoginForm onLogin={onLogin} />);

    fireEvent.changeText(screen.getByPlaceholderText('Email'), 'user@example.com');
    fireEvent.changeText(screen.getByPlaceholderText('Password'), 'secret123');
    fireEvent.press(screen.getByRole('button', { name: /login/i }));

    expect(onLogin).toHaveBeenCalledWith({
      email: 'user@example.com',
      password: 'secret123',
    });
  });
});

36. How do you mock native modules in Jest?

// jest.setup.js — mock AsyncStorage
jest.mock('@react-native-async-storage/async-storage', () =>
  require('@react-native-async-storage/async-storage/jest/async-storage-mock')
);

// Mock a custom native module
jest.mock('react-native', () => {
  const RN = jest.requireActual('react-native');
  RN.NativeModules.BatteryModule = {
    getBatteryLevel: jest.fn().mockResolvedValue(0.85),
  };
  return RN;
});
// package.json
{
  "jest": {
    "preset": "react-native",
    "setupFilesAfterFramework": ["./jest.setup.js"]
  }
}

Advanced Topics

37. What is the New Architecture in React Native?

The New Architecture replaces the bridge with JSI and introduces:

Component Old New
Native modules Bridge (async JSON) TurboModules (JSI, synchronous)
Renderer UIManager / Shadow tree Fabric (synchronous, concurrent)
Layout engine Yoga (separate thread) Yoga on UIThread via Fabric
State updates Batched async Concurrent React (transitions)

Enable in React Native 0.71+:

// android/gradle.properties
newArchEnabled=true
# ios/Podfile
:fabric_enabled => true

38. How does React Native handle gestures?

Using React Native Gesture Handler (replaces built-in responder system):

import { GestureDetector, Gesture } from 'react-native-gesture-handler';
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';

function DraggableBox() {
  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);

  const drag = Gesture.Pan()
    .onUpdate((event) => {
      translateX.value = event.translationX;
      translateY.value = event.translationY;
    })
    .onEnd(() => {
      translateX.value = withSpring(0);
      translateY.value = withSpring(0);
    });

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

  return (
    <GestureDetector gesture={drag}>
      <Animated.View style={[styles.box, animatedStyle]} />
    </GestureDetector>
  );
}

39. How do you implement code splitting / lazy loading in React Native?

import React, { Suspense, lazy } from 'react';
import { ActivityIndicator } from 'react-native';

// Lazy load heavy screen
const HeavyScreen = lazy(() => import('./HeavyScreen'));

function Navigator() {
  return (
    <Suspense fallback={<ActivityIndicator />}>
      <HeavyScreen />
    </Suspense>
  );
}

With React Navigation, use lazy option on navigators to defer screen component loading.


40. What is Metro and how does it differ from webpack?

Metro is React Native's JavaScript bundler.

Feature Metro Webpack
Target React Native (mobile) Web browsers
Speed Optimised for RN (incremental) Configurable
Config metro.config.js webpack.config.js
Code splitting Basic Advanced (dynamic import)
Hot reload Fast Refresh HMR
Tree shaking Limited Full

41. How do you handle environment variables in React Native?

React Native doesn't have a built-in .env loader. Common approaches:

// Using react-native-config (recommended)
// .env
API_URL=https://api.example.com
APP_ENV=production

// Usage
import Config from 'react-native-config';
const apiUrl = Config.API_URL;

With Expo:

// app.config.js
export default {
  extra: {
    apiUrl: process.env.API_URL ?? 'http://localhost:3000',
  },
};

// Usage
import Constants from 'expo-constants';
const { apiUrl } = Constants.expoConfig.extra;

Never put secrets in environment variables accessible to the JS bundle — they can be extracted from the APK/IPA. Use a backend to proxy sensitive calls.


42. How do you handle offline mode in React Native?

import NetInfo from '@react-native-community/netinfo';
import { useEffect, useState } from 'react';

function useNetworkStatus() {
  const [isOnline, setIsOnline] = useState(true);

  useEffect(() => {
    const unsubscribe = NetInfo.addEventListener((state) => {
      setIsOnline(state.isConnected ?? false);
    });
    return unsubscribe;
  }, []);

  return isOnline;
}

// Usage
function App() {
  const isOnline = useNetworkStatus();
  return (
    <View>
      {!isOnline && <OfflineBanner />}
      <MainContent />
    </View>
  );
}

For offline-first apps, combine with TanStack Query's persistQueryClient + AsyncStorage, or WatermelonDB for full offline sync.


43. What is CodePush and what are OTA updates?

OTA (over-the-air) updates push JS bundle changes directly to users without an app store review.

Service Provider Works with
CodePush Microsoft App Center Bare React Native
Expo Updates Expo Expo managed + bare
EAS Update Expo Expo projects
// EAS Update: push OTA update
eas update --branch production --message "Fix login bug"

Limitations: OTA can only update JavaScript and assets. Native code changes always require a full app store release.


44. How do you debug React Native apps?

Tool Use case
Flipper Network, storage, layout inspection, Redux DevTools
React DevTools Component tree, props, hooks inspection
Chrome DevTools JS debugger (via remote debugging)
Hermes Profiler JS performance profiling
Android Studio Profiler Memory, CPU, network on Android
Xcode Instruments Memory, CPU, GPU on iOS
console.log Quick value inspection
# Start Metro with dev tools
npx react-native start

# Enable remote debugging
# Shake device or Cmd+D → "Debug with Chrome"

45. What is Turbo Modules?

TurboModules replace the old bridge-based Native Modules in the New Architecture.

Key improvements:

  • Lazy initialization — modules load on first use, not at startup
  • Synchronous calls — direct C++ calls via JSI (no async bridge)
  • Type safety — Codegen generates interfaces from Flow/TypeScript specs
// Native module spec (TypeScript)
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
  getBatteryLevel(): Promise<number>;
}

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

46. How do you handle app state and background tasks?

import { AppState } from 'react-native';
import { useEffect, useRef } from 'react';

function useAppState(onForeground, onBackground) {
  const appState = useRef(AppState.currentState);

  useEffect(() => {
    const sub = AppState.addEventListener('change', (nextState) => {
      if (appState.current.match(/inactive|background/) && nextState === 'active') {
        onForeground?.();
      } else if (nextState.match(/inactive|background/)) {
        onBackground?.();
      }
      appState.current = nextState;
    });
    return () => sub.remove();
  }, []);
}

// Background tasks with expo-background-fetch
import * as BackgroundFetch from 'expo-background-fetch';
import * as TaskManager from 'expo-task-manager';

TaskManager.defineTask('BACKGROUND_SYNC', async () => {
  await syncData();
  return BackgroundFetch.BackgroundFetchResult.NewData;
});

await BackgroundFetch.registerTaskAsync('BACKGROUND_SYNC', {
  minimumInterval: 15 * 60, // 15 minutes
});

47. How do you implement biometric authentication?

import * as LocalAuthentication from 'expo-local-authentication';

async function authenticateWithBiometrics() {
  const hasHardware = await LocalAuthentication.hasHardwareAsync();
  const isEnrolled = await LocalAuthentication.isEnrolledAsync();

  if (!hasHardware || !isEnrolled) {
    return fallbackToPIN();
  }

  const result = await LocalAuthentication.authenticateAsync({
    promptMessage: 'Confirm your identity',
    fallbackLabel: 'Use PIN',
    disableDeviceFallback: false,
  });

  if (result.success) {
    unlockApp();
  } else {
    Alert.alert('Authentication failed');
  }
}

48. What are common React Native anti-patterns?

Anti-pattern Problem Fix
Inline styles in render New object on every render Use StyleSheet.create()
Anonymous functions in renderItem Breaks React.memo Use useCallback
ScrollView for long lists Renders all items at once Use FlatList
useState for server state Stale data, no caching Use TanStack Query
Secrets in .env / JS bundle Extractable from APK Use backend proxy
Missing keyExtractor Unstable reconciliation Always provide unique key
async in useEffect directly Memory leaks, race conditions Wrap in inner async fn with cleanup
Hardcoded platform strings Breaks cross-platform Use Platform.select

49. React Native vs Flutter vs Native — when to choose each?

Factor React Native Flutter Native (iOS/Android)
Language JavaScript / TypeScript Dart Swift / Kotlin
Code sharing ~85-90% ~85-90% 0%
Performance Near-native (JSI) Near-native (Impeller) Native
UI fidelity Native components Custom (pixel-perfect) Native
Ecosystem npm (vast) pub.dev Platform SDKs
Team skills Web devs Dart learners Mobile specialists
Hot reload Yes Yes Limited
Best for Web teams going mobile Pixel-perfect UI / new projects Maximum performance + platform features

50. How do you prepare a React Native app for production?

# 1. Enable Hermes
# android/app/build.gradle: enableHermes: true

# 2. Enable ProGuard (Android)
# android/app/build.gradle: minifyEnabled = true

# 3. Configure app signing
# android/app/build.gradle: signingConfig

# 4. Build production bundle
npx react-native bundle \
  --platform android \
  --dev false \
  --entry-file index.js \
  --bundle-output android/app/src/main/assets/index.android.bundle

# 5. Build release APK / AAB
cd android && ./gradlew bundleRelease

# 6. Build iOS release
cd ios && xcodebuild archive -scheme MyApp -configuration Release

Pre-launch checklist:

  • Remove all console.log calls (or use a logger that strips in prod)
  • Disable remote debugger in production
  • Test on real low-end devices
  • Set up crash reporting (Sentry / Bugsnag)
  • Configure app icons and splash screen
  • Handle all error boundaries

Common Mistakes

Mistake Why it's a problem Fix
Not using keyExtractor List items remount unexpectedly Always provide unique stable keys
Using index as key Breaks reconciliation on reorder Use item ID
Blocking JS thread 60fps drops, unresponsive UI Use InteractionManager or worklets
Not cleaning up in useEffect Memory leaks, stale callbacks Return cleanup function
Using ScrollView for large lists All items rendered upfront Use FlatList
Secrets in bundle Extractable from APK/IPA Backend proxy for sensitive calls
No offline handling App crashes without internet Check NetInfo, cache with TanStack Query
Missing error boundaries Crash on any JS error Wrap screens in ErrorBoundary

React Native vs Flutter vs React Native Web

Feature React Native Flutter RN + React Native Web
iOS
Android
Web Via RN Web Via Flutter Web
Desktop Via Electron ✅ (macOS/Linux/Win) Partial
TV ✅ (tvOS/Android TV)
Code sharing Mobile ~90% Mobile ~90% All platforms ~75%

FAQ

Q: Is React Native still relevant in 2025?
Yes. Meta, Shopify, Discord, and Microsoft use React Native in production. The New Architecture (JSI + Fabric) closes the performance gap with native, and Expo has significantly improved developer experience.

Q: Do I need to know iOS/Android to use React Native?
Not for day-to-day development. But understanding native concepts (lifecycle, permissions, background tasks) helps when debugging platform-specific issues or writing native modules.

Q: What's the difference between React Native CLI and Expo CLI?
React Native CLI (bare) gives full control and requires Xcode/Android Studio. Expo CLI sets up a managed project with cloud builds (EAS), pre-built native modules, and simpler workflow — recommended for most projects.

Q: How do I handle different screen sizes in React Native?
Use Dimensions.get('window'), useWindowDimensions() hook, or % units in styles. For responsive layouts, prefer Flexbox percentages over fixed pixel values.

Q: Can React Native apps access all device APIs?
Most APIs have community or Expo libraries. Very new or specialised APIs may need a custom native module. The Expo library ecosystem covers the vast majority of common needs.

Q: What is the best state management for React Native in 2025?
For server state: TanStack Query. For client state: Zustand (simple) or Redux Toolkit (complex). Avoid over-engineering — start with useState + Context and add libraries when genuinely needed.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools