Back to Articles

React Native Senior Developer Interview Questions & Answers

8 min read
React Native Senior Developer Interview Questions

This comprehensive guide covers essential topics for senior React Native developer interviews with practical examples and real-world analogies.

1. Performance Optimization

Question: How do you optimize FlatList performance for large datasets?

Analogy: Think of FlatList like a library reading room. Instead of displaying all books at once, you only show what's visible on the current shelf, and load the next shelf as the reader scrolls.

Key Optimization Techniques:

javascript
const OptimizedList = ({ data }) => {
  const renderItem = useCallback(({ item }) => , []);
  const keyExtractor = useCallback((item) => item.id.toString(), []);

  return (
     ({
        length: ITEM_HEIGHT,
        offset: ITEM_HEIGHT * index,
        index,
      })}
      removeClippedSubviews={true}
      maxToRenderPerBatch={10}
      initialNumToRender={10}
      windowSize={5}
    />
  );
};

const ListItem = React.memo(({ item }) => (
  {item.title}
));

Critical Points:

  • Use React.memo to prevent unnecessary re-renders
  • Implement getItemLayout for fixed-height items (tells FlatList exact dimensions upfront)
  • Set windowSize={5} to render 5 screens worth of content
  • Enable removeClippedSubviews to unmount off-screen items

2. Native Modules Integration

Question: How do you create and use a native module in React Native?

Analogy: Think of native modules as translators between two people who speak different languages. JavaScript speaks to the native code (iOS/Android) through this bridge, allowing access to platform-specific features.

iOS Implementation (Simplified):

objective-c
// RNBiometricAuth.m
#import "RNBiometricAuth.h"
#import 

@implementation RNBiometricAuth

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(authenticate:(NSString *)reason
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
  LAContext *context = [[LAContext alloc] init];
  [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
               localizedReason:reason
                         reply:^(BOOL success, NSError *error) {
    if (success) {
      resolve(@{@"success": @YES});
    } else {
      reject(@"AUTH_FAILED", @"Authentication failed", error);
    }
  }];
}

@end

JavaScript Usage:

javascript
import { NativeModules } from 'react-native';
const { RNBiometricAuth } = NativeModules;

const authenticate = async () => {
  try {
    const result = await RNBiometricAuth.authenticate("Please authenticate");
    return result.success;
  } catch (error) {
    return false;
  }
};

Key Concepts:

  • Use RCT_EXPORT_MODULE() to expose module to JavaScript
  • Use RCT_EXPORT_METHOD for async methods with Promise support
  • Native modules run on separate thread, perfect for heavy operations

3. State Management

Question: Compare Redux, MobX, and Zustand. When would you use each?

Analogy: Think of state management like organizing a company:

  • Redux is like a corporate office with strict procedures and documentation
  • Zustand is like a small startup with minimal bureaucracy
  • Context API is like a family business - simple and direct
Zustand (Recommended for most cases):

javascript
import create from 'zustand';

const useStore = create((set) => ({
  user: null,
  loading: false,

  fetchUser: async (userId) => {
    set({ loading: true });
    const response = await fetch(`/api/users/${userId}`);
    const data = await response.json();
    set({ user: data, loading: false });
  },

  updateUser: (updates) => set((state) => ({
    user: { ...state.user, ...updates }
  })),
}));

// Usage
const UserProfile = () => {
  const { user, fetchUser } = useStore();
  useEffect(() => { fetchUser('123'); }, []);
  return {user?.name};
};

Redux Toolkit (For large enterprise apps):

javascript
const userSlice = createSlice({
  name: 'user',
  initialState: { data: null, loading: false },
  reducers: {
    updateUser: (state, action) => {
      state.data = { ...state.data, ...action.payload };
    },
  },
});

When to Use:

  • Redux: 50+ screens, time-travel debugging, strict team structure
  • Zustand: Most apps (10-50 screens), simple API, great performance
  • Context API: Small apps (<10 screens), theme/auth only

4. Navigation Architecture

Question: How do you implement deep linking with React Navigation?

Analogy: Think of deep linking like giving someone directions to a specific room in a building. Instead of saying "go to the building," you say "go to Building A, 3rd floor, Room 305" - they land exactly where they need to be.

Simple Deep Linking Setup:

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

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

function App() {
  return (
    
      
        
        
      
    
  );
}

How it works:

  • URL myapp://profile/123 automatically navigates to ProfileScreen with userId=123
  • Works with both custom schemes (myapp://) and universal links (https://myapp.com)
  • Configure in iOS Info.plist and Android AndroidManifest.xml

5. Testing Strategies

Question: How do you write effective tests for React Native components?

Analogy: Testing is like having a safety net for circus performers. Unit tests catch small mistakes (individual tricks), integration tests catch coordination issues (routines), and E2E tests ensure the whole show works.

Essential Test Structure:

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

describe('UserProfile', () => {
  it('renders user data after loading', async () => {
    const { getByText, getByTestId } = render();

    // 1. Check loading state
    expect(getByTestId('loading-spinner')).toBeTruthy();

    // 2. Wait for async data
    await waitFor(() => {
      expect(getByText('John Doe')).toBeTruthy();
    });
  });

  it('handles button press correctly', () => {
    const onPress = jest.fn();
    const { getByText } = render(

Testing Priorities:

  1. Unit Tests: Test pure functions and utility logic
  2. Component Tests: Test user interactions (button press, form input)
  3. Integration Tests: Test component communication
  4. E2E Tests: Test critical user flows (login, checkout)

6. Code Splitting & Lazy Loading

Question: How do you implement code splitting in React Native?

Analogy: Think of code splitting like streaming a movie vs downloading it entirely first. You load what you need now, and download the rest when required - faster initial load, better user experience.

Lazy Loading Components:

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

// Lazy load heavy components
const HeavyChart = lazy(() => import('./HeavyChart'));

const DashboardScreen = () => {
  const [showChart, setShowChart] = useState(false);

  return (
    
      

Metro Config Optimization:

javascript
// metro.config.js
module.exports = {
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        inlineRequires: true, // Loads modules only when needed
      },
    }),
  },
};

Impact: Can reduce initial bundle size by 30-40% for large apps

7. Memory Management

Question: How do you prevent memory leaks in React Native?

Analogy: Memory leaks are like leaving the faucet running. Each unmounted component that doesn't clean up leaves a drip - eventually you flood the system. Always turn off the tap (cleanup) when leaving.

Essential Cleanup Pattern:

javascript
import { useEffect, useRef } from 'react';

const UserComponent = () => {
  const isMounted = useRef(true);

  useEffect(() => {
    isMounted.current = true;

    // Cleanup when component unmounts
    return () => {
      isMounted.current = false;
    };
  }, []);

  // Safe async operation
  const fetchData = async () => {
    const response = await fetch('/api/data');
    const data = await response.json();

    // Only update if component still mounted
    if (isMounted.current) {
      setData(data);
    }
  };

  // Cleanup event listeners
  useEffect(() => {
    const subscription = EventEmitter.addListener('update', handleUpdate);

    return () => {
      subscription.remove(); // Critical: Always cleanup
    };
  }, []);

  return ...;
};

Common Memory Leak Sources:

  1. Event Listeners: Always call .remove() in cleanup
  2. Timers: Clear all setTimeout/setInterval
  3. Async Operations: Check isMounted before setState
  4. Native Modules: Release native resources in cleanup

Key Takeaways

Performance First

  • Optimize FlatList with memoization and windowing
  • Lazy load heavy components to reduce bundle size
Platform Knowledge
  • Understand native module bridges for iOS and Android
  • Know when to drop down to native code
Smart State Management
  • Choose tools based on app size (Context < Zustand < Redux)
  • Keep state close to where it's used
Production Ready
  • Write tests for critical user flows
  • Always cleanup subscriptions and listeners
  • Implement proper error boundaries

Final Thoughts

Senior React Native positions require more than just coding skills. You need to understand:

  • Why certain patterns exist, not just how to use them
  • When to optimize vs when premature optimization hurts
  • How to balance native power with cross-platform benefits
The best way to prepare? Build real apps, profile performance, and understand the trade-offs of every decision.

Frequently Asked Questions (FAQ)

Q: How do I prepare for senior React Native interviews?

Focus on: 1) FlatList performance optimization (60% of performance questions), 2) Bridge understanding (JS ↔ Native communication), 3) State management at scale (Context API vs Redux vs Zustand), 4) Build sample app with: pagination, image caching, offline support, 5) Know when React Native is wrong choice (games, AR/VR, heavy animations), 6) Practice system design (design WhatsApp, Instagram with RN), 7) Review Hermes, JSI, and Fabric (new architecture).

Q: Should I learn native iOS/Android for senior React Native roles?

Yes, understanding is crucial (not mastery). Know: 1) iOS: Swift basics, CocoaPods, Xcode project structure, AppDelegate, Info.plist, 2) Android: Kotlin basics, Gradle, AndroidManifest, MainActivity, 3) How to write native modules (80% of senior roles need this), 4) Debugging native crashes (symbolication, Xcode debugger, Android Studio logcat), 5) When to use native vs JavaScript (camera, Bluetooth, background tasks favor native).

Q: What's the difference between Expo and bare React Native workflow?

Expo (managed): Pre-configured, over-the-air updates, easier setup, limited to Expo SDK (no custom native modules). Bare workflow: Full native access, any native module, custom native code, requires Xcode/Android Studio. Senior roles expect: knowledge of when to use each (Expo for MVPs/simple apps, bare for complex apps), how to migrate Expo → bare, and experience with both. Most production apps use bare workflow.

Q: How do I explain React Native performance bottlenecks in interviews?

Use this framework: 1) Identify bottleneck type (JS thread, UI thread, or bridge), 2) JS thread: Heavy computations, large state updates → Solution: useMemo, lazy loading, worker threads, 3) UI thread: Complex layouts, shadows, blur → Solution: shouldComponentUpdate, FlatList optimization, 4) Bridge: Frequent JS ↔ Native calls → Solution: batching, JSI (synchronous calls), 5) Always mention profiling first (React DevTools Profiler, Flipper).

Q: What are red flags that make React Native the wrong choice?

Avoid React Native for: 1) Real-time games (Unity/Unreal better), 2) AR/VR apps (native ARKit/ARCore required), 3) Apps with 50+ complex animations (native performs better), 4) Apps requiring background execution (geolocation tracking, music players - native easier), 5) Apps needing newest OS features immediately (native gets APIs first, RN waits 3-6 months). Demonstrate you know trade-offs, not just RN evangelism.

Q: How do I handle "Why React Native over Flutter?" in interviews?

Balanced answer showing maturity: Choose React Native when: 1) Team knows JavaScript/React (retraining cost), 2) Large npm ecosystem needed (400K+ packages), 3) Need to share code with React web app, 4) Mature ecosystem (2015 vs Flutter 2017). Choose Flutter when: Better performance needed (closer to native), simpler state management (Provider), single company backing (Google vs Facebook/Meta + community). Senior answer: "Both are great, choice depends on team and requirements."

Q: What salary should I expect for senior React Native roles in 2025?

US market: $120K-180K (SF/NYC: $150K-200K). Europe: €55K-85K (€70K-110K London). Remote: $100K-140K. Factors: Years with React Native (3+ for senior), native module experience (+15-25%), published apps with 100K+ users, contributions to React Native core or popular libraries, full-stack capabilities (Node.js backend +10-15%), system design expertise. React Native developers typically earn 10-15% less than native iOS/Android but have 2X job opportunities.

Ali Mert Güleç

Ali Mert Güleç

Mobile-Focused Full Stack Engineer

Passionate about creating exceptional mobile experiences with 7+ years of expertise in iOS, Android, and React Native development. I've helped businesses worldwide transform their ideas into successful applications with millions of active users.

7+
Years Exp.
50+
Apps Built
100%
Satisfaction
4.9/5
Rating