Top 58 React Native Interview Questions & Answers (2026)
About React Native
Top 100 React Native interview questions covering components, navigation, state management, animations, native modules, performance optimization, and cross-platform development. Companies hiring for React Native roles test this knowledge at every stage — from first-round screens that check the basics to final-round conversations about real-world trade-offs.
What to Expect in a React Native Interview
Expect a mix of conceptual and practical React Native questions: clear definitions and core-concept checks for junior roles, hands-on scenario questions for mid-level roles, and architecture or trade-off discussions for senior roles. Interviewers usually move from foundational topics toward the kind of problems you'd actually face on the job.
How to Use This Guide
Work through the React Native questions in order — Beginner, then Intermediate, then Advanced — so each concept builds on the last. Every question has its own page; bookmark the ones that trip you up and revisit them the day before your interview.
Curated by Tech Baithak Editorial Team · Last updated: May 2026
Core concepts every React Native developer must know.
01
What is React Native?
React Native is an open-source framework created by Facebook (Meta) in 2015 for building native mobile applications for iOS and Android using JavaScript and React. Unlike hybrid frameworks (Cordova, Ionic) that render web views inside a native shell, React Native compiles JavaScript components to genuinely native UI elements — so the app looks and feels like a real native app. Key characteristics: (1) Write once, run on iOS and Android: share most code between platforms while still accessing platform-specific APIs; (2) Native rendering: React components map to real native views (UIView on iOS, View on Android) — not a WebView; (3) JavaScript bridge / New Architecture: JavaScript runs in a separate JS thread and communicates with native code. The New Architecture (JSI + Fabric + TurboModules) dramatically improves this communication; (4) Hot Reloading / Fast Refresh: see code changes instantly without rebuilding the app; (5) React paradigm: same component model, hooks, and state management as React web. Used by: Meta (Facebook, Instagram), Shopify, Microsoft (Outlook), Walmart, Airbnb (formerly), Discord. React Native vs Flutter: React Native uses JavaScript + native components; Flutter uses Dart + its own rendering engine (Skia/Impeller). React Native has a larger community; Flutter has more consistent cross-platform rendering.
02
What is the difference between React Native and React?
React is a JavaScript library for building web user interfaces — it renders to the browser DOM. React Native uses the same React paradigm (components, hooks, state, props, JSX) but renders to native mobile UI instead of the browser DOM. Key similarities: component-based architecture, JSX syntax, hooks (useState, useEffect, useContext, useCallback, useMemo), props and state, same JavaScript, same Redux/Zustand/Recoil state management libraries, same testing patterns. Key differences: (1) No HTML tags: React Native uses View instead of div, Text instead of p/span/h1, Image instead of img, TextInput instead of input; (2) No CSS: React Native uses a JavaScript-based StyleSheet API. Subset of CSS — Flexbox (default), no grid, no CSS cascade; (3) No browser APIs: no window, document, localStorage. Use AsyncStorage, platform APIs; (4) Platform-specific code: some components/APIs differ per platform (iOS vs Android). Use Platform.OS or .ios.js/.android.js file extensions; (5) Navigation: browser has built-in URL routing; React Native needs a library (React Navigation, Expo Router); (6) Performance model: React targets 60fps DOM updates; React Native targets 60fps native rendering across a JS-native bridge. Code that's valid in one is NOT automatically valid in the other.
03
What are the core components in React Native?
React Native provides a set of Core Components that map to native UI elements on each platform: View: the most fundamental container component — equivalent to a div. Used for layout, styling, grouping: <View style={{ flex: 1, backgroundColor: "white" }}>. Maps to UIView (iOS) and View (Android). Text: the ONLY way to display text — all text must be inside Text: <Text style={{ fontSize: 16, color: "#333" }}>Hello!</Text>. Image: display local or remote images: <Image source={require("./logo.png")} /> or <Image source={{ uri: "https://example.com/img.jpg" }} style={{ width: 100, height: 100 }} />. TextInput: text input field: <TextInput value={text} onChangeText={setText} placeholder="Type here" />. ScrollView: scrollable container (loads all children at once — avoid for long lists). FlatList: performant list for large datasets (lazy renders only visible items). SectionList: FlatList with section headers. TouchableOpacity: tappable wrapper with opacity feedback. TouchableHighlight: highlights on press. Pressable: modern, flexible press handler with states. Button: simple platform-native button. Switch: toggle switch. ActivityIndicator: loading spinner. Modal: overlay screen. KeyboardAvoidingView: adjusts layout when keyboard appears. SafeAreaView: avoids notch/home indicator areas.
04
What is the StyleSheet API in React Native?
React Native uses a JavaScript-based StyleSheet API instead of CSS. Styles are written as JavaScript objects and applied via the style prop. StyleSheet.create(): creates an optimized style object — validates styles in development, sends style IDs over the bridge (more efficient than raw objects): 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 World</Text> </View> ); }. Differences from CSS: (1) camelCase properties (backgroundColor not background-color); (2) No class names or selectors — styles applied per component; (3) Numbers without units (pixels by default) — fontSize: 16 not "16px"; (4) No inheritance (except inside Text components for text-related styles); (5) Flexbox is the primary layout system and is default; (6) No shorthand properties in most cases (marginVertical: 8 instead of margin: 8px 0); (7) No CSS cascade — styles don't inherit from parent views. Inline styles: <View style={{ flex: 1, padding: 16 }}> — valid but less efficient (creates new object each render). Style arrays: style={[styles.base, isActive && styles.active]} — merge multiple style objects, falsy values ignored.
05
How does Flexbox work in React Native?
React Native uses Flexbox as its primary layout system — similar to CSS Flexbox but with different defaults. Key difference from web CSS Flexbox: flexDirection defaults to "column" (not "row"). alignContent defaults to "flex-start". Core properties: flexDirection: "row" | "column" | "row-reverse" | "column-reverse" — direction of the main axis. Default: column (vertical). justifyContent: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly" — align along main axis. alignItems: "flex-start" | "flex-end" | "center" | "stretch" | "baseline" — align along cross axis. flex: 1 — component grows to fill available space. Multiple children with flex: 1 share space equally. flexWrap: "wrap" | "nowrap". alignSelf — override parent's alignItems for one child. Common patterns: // Center content in screen: { flex: 1, justifyContent: "center", alignItems: "center" } // Row of items: { flexDirection: "row", justifyContent: "space-between" } // Fill remaining space: { flex: 1 } // Absolute positioning: { position: "absolute", top: 0, left: 0, right: 0 }. Width/Height: width: 100 (fixed px), width: "50%" (percentage of parent), width: "auto". Position: relative (default) or absolute. Absolute removes from flow, positions relative to nearest positioned ancestor.
06
What is the difference between FlatList and ScrollView?
Both allow scrollable content but differ fundamentally in how they render children — this makes a huge performance difference for large datasets: ScrollView: renders ALL children at once into memory, regardless of whether they're visible on screen. Pros: simple API, supports any type of content (mixed layout), supports vertical and horizontal scroll, supports zoom (pinch). Cons: poor performance with many items (all loaded upfront), high memory usage, slow initial render for large lists. Use when: content is relatively small (≤20-50 items), content is heterogeneous (not a uniform list), need pinch-to-zoom. <ScrollView> {items.map(item => <ItemComponent key={item.id} item={item} />)} </ScrollView>. FlatList: renders only items visible on screen plus a configurable window. Items outside the viewport are unmounted (or virtualized). Pros: excellent performance for large lists, constant memory usage, lazy rendering, built-in pull-to-refresh, built-in infinite scroll (onEndReached). Cons: more complex API, requires unique key (keyExtractor), can't have arbitrary non-list content easily. Use for: any list of uniform items, especially 20+ items. <FlatList data={items} keyExtractor={item => item.id.toString()} renderItem={({ item }) => <ItemComponent item={item} />} onEndReached={loadMore} onEndReachedThreshold={0.5} refreshing={isRefreshing} onRefresh={handleRefresh} />. SectionList: like FlatList but with section headers — for grouped data (contacts list with alphabetical headers).
07
What is React Navigation?
React Navigation is the most popular navigation library for React Native, providing a complete navigation solution. React Native has no built-in navigation (unlike web browsers). Installation: npm install @react-navigation/native @react-navigation/stack @react-navigation/bottom-tabs react-native-screens react-native-safe-area-context. Setup: wrap app in NavigationContainer: import { NavigationContainer } from "@react-navigation/native"; export default function App() { return ( <NavigationContainer> <RootNavigator /> </NavigationContainer> ); }. Stack Navigator: push/pop screens (back gesture, back button): import { createNativeStackNavigator } from "@react-navigation/native-stack"; const Stack = createNativeStackNavigator(); function RootNavigator() { return ( <Stack.Navigator initialRouteName="Home"> <Stack.Screen name="Home" component={HomeScreen} /> <Stack.Screen name="Detail" component={DetailScreen} /> </Stack.Navigator> ); } // Navigating: navigation.navigate("Detail", { id: 123 }) navigation.goBack(). Bottom Tab Navigator: tab bar at bottom: const Tab = createBottomTabNavigator(); <Tab.Navigator> <Tab.Screen name="Home" component={HomeScreen} /> <Tab.Screen name="Profile" component={ProfileScreen} /> </Tab.Navigator>. Accessing navigation: via props (navigation, route) or hooks: const navigation = useNavigation(); const route = useRoute();. Expo Router: file-based routing (like Next.js) — modern alternative for Expo projects.
08
What is the difference between TouchableOpacity, TouchableHighlight, and Pressable?
All three make content tappable, but with different visual feedback and capabilities: TouchableOpacity: the most commonly used. Reduces opacity of the wrapped content on press, creating a visual feedback effect: <TouchableOpacity onPress={handlePress} activeOpacity={0.7}> <Text>Tap Me</Text> </TouchableOpacity>. activeOpacity (0-1): how opaque during press (default 0.2). Simple, clean effect. TouchableHighlight: highlights the wrapped content with an underlay color on press. Requires a single child (wrap in View if needed). Can look heavy on complex UIs: <TouchableHighlight onPress={handlePress} underlayColor="#ddd"> <View><Text>Tap Me</Text></View> </TouchableHighlight>. Pressable (modern — recommended): most flexible — provides pressed state to children, supports onLongPress, onPressIn, onPressOut, custom feedback, HitSlop. Can use a function as child to access pressed state: <Pressable onPress={handlePress} style={({ pressed }) => [styles.button, pressed && styles.pressed]} > {({ pressed }) => <Text style={{ opacity: pressed ? 0.7 : 1 }}>Tap Me</Text>} </Pressable>. Recommendation: prefer Pressable for new code — it's the most powerful and is the direction React Native is heading. TouchableOpacity is still very common and perfectly valid. Avoid TouchableNativeFeedback (Android-only ripple) unless you specifically want the Android ripple effect.
09
What is AsyncStorage in React Native?
AsyncStorage is a simple, asynchronous, unencrypted, persistent key-value storage system for React Native — the mobile equivalent of localStorage (but asynchronous). It's the simplest way to persist data between app sessions. The community package @react-native-async-storage/async-storage is the standard implementation (the original was removed from React Native core). Installation: npm install @react-native-async-storage/async-storage. API: import AsyncStorage from "@react-native-async-storage/async-storage"; // Store: await AsyncStorage.setItem("@user_token", token); // Retrieve: const token = await AsyncStorage.getItem("@user_token"); // null if not found // Remove: await AsyncStorage.removeItem("@user_token"); // Check all keys: const keys = await AsyncStorage.getAllKeys(); // Batch operations (efficient): await AsyncStorage.multiSet([["@key1", "val1"], ["@key2", "val2"]]); const values = await AsyncStorage.multiGet(["@key1", "@key2"]); // Clear ALL data: await AsyncStorage.clear();. Objects — must JSON encode: // Store object: await AsyncStorage.setItem("@user", JSON.stringify(user)); // Retrieve object: const stored = await AsyncStorage.getItem("@user"); const user = stored ? JSON.parse(stored) : null;. Limitations: strings only (JSON serialize objects), unencrypted (don't store sensitive data — use react-native-keychain or react-native-secure-storage), limited to 6MB (varies by platform), asynchronous. For sensitive data: use react-native-keychain (accesses iOS Keychain / Android Keystore). For complex structured data: consider WatermelonDB or SQLite.
10
What is Expo?
Expo is a platform and set of tools built around React Native that simplifies building, deploying, and publishing React Native apps. It provides an SDK of pre-built native modules, a managed workflow, and cloud build services. Two workflows: (1) Managed workflow (Expo Go): Expo handles everything — no need for Xcode or Android Studio. Write JavaScript, Expo handles native compilation. Can preview instantly in the Expo Go app on your phone. Limitations: can only use Expo SDK's built-in native modules (not arbitrary native code). Great for beginners, prototypes, many production apps; (2) Bare workflow: eject from managed to have full access to native code (use any npm package with native code). Still uses Expo SDK, but now also has ios/ and android/ folders you control. Expo SDK: pre-built modules for: camera, location, notifications, sensors, filesystem, barcode scanner, face detection, audio, video, SQLite, font loading, and 100+ more — all cross-platform with consistent API. Expo Router: file-based routing (pages directory → routes). EAS (Expo Application Services): cloud build service — build iOS/Android binaries in the cloud without local Xcode/Android Studio: eas build --platform all. Also handles OTA (over-the-air) updates and submission to App Store/Play Store. Starting a project: npx create-expo-app MyApp. Development: npx expo start → scan QR code with Expo Go app.
11
What are hooks in React Native?
React Native uses the same React hooks as React web — they work identically. All standard hooks apply: useState: local component state: const [count, setCount] = useState(0);. useEffect: side effects — data fetching, subscriptions, cleanup. Runs after render: useEffect(() => { fetchData(); return () => { cleanup(); }; }, [dependency]);. useCallback: memoize a function — prevents unnecessary re-renders of child components that receive the function as a prop: const handlePress = useCallback(() => { doSomething(); }, [dependency]);. useMemo: memoize computed value: const expensiveValue = useMemo(() => computeExpensive(data), [data]);. useRef: access a component or store a mutable value without re-render: const inputRef = useRef(null); inputRef.current.focus();. useContext: access context value: const theme = useContext(ThemeContext);. useReducer: complex state logic: const [state, dispatch] = useReducer(reducer, initialState);. React Native-specific hooks (from libraries): useFocusEffect (React Navigation) — runs when screen is focused; useNavigation (React Navigation) — access navigation object anywhere; useSafeAreaInsets (react-native-safe-area-context) — get safe area insets for notch/home indicator; useColorScheme (built-in) — detect dark/light mode: const colorScheme = useColorScheme(); // "dark" | "light" | null. Custom hooks: same pattern as React web — extract reusable stateful logic into functions starting with "use".
12
What is the Platform API in React Native?
The Platform module allows you to write platform-specific code and detect which platform the app is running on. Platform.OS: returns "ios", "android", "windows", "macos", or "web": import { Platform } from "react-native"; if (Platform.OS === "ios") { // iOS specific code } const statusBarHeight = Platform.OS === "ios" ? 44 : 24;. Platform.select(): cleaner way to select platform-specific values: const styles = StyleSheet.create({ container: { paddingTop: Platform.select({ ios: 44, android: 0, default: 0, }), }, }); const shadow = Platform.select({ ios: { shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, }, android: { elevation: 4, }, });. Platform.Version: OS version — string on iOS ("17.0"), number on Android (33 = Android 13). Platform-specific files: the cleanest approach for large platform-specific differences. Create two files: Button.ios.tsx and Button.android.tsx. React Native automatically picks the correct file when you import ./Button. Also works with .native.tsx (native vs web) and .web.tsx. isTV / isTVOS: detect TV platforms. isPad (iOS only): detect iPad. Best practice: minimize platform-specific code — the more shared code, the less maintenance. Use platform files for fundamentally different UX, not minor style differences.
13
What is Metro bundler in React Native?
Metro is the JavaScript bundler for React Native — it takes your JavaScript source files and bundles them into a single bundle that the app loads. Similar to Webpack for web but optimized for mobile. Key features: (1) Fast bundling: Metro is optimized for mobile development — incremental builds, parallel processing; (2) Hot Module Replacement (HMR) / Fast Refresh: when you save a file, Metro sends only the changed modules to the running app — preserves component state across code changes; (3) Dependency resolution: resolves imports/requires, handles platform-specific files (.ios.js, .android.js); (4) Asset management: handles images, fonts, and other assets with automatic resolution for @2x/@3x densities; (5) Source maps: generates source maps for debugging. Starting Metro: runs automatically when you run npx react-native start or npx expo start. Default port: 8081. metro.config.js: configuration file for Metro: const { getDefaultConfig } = require("@react-native/metro-config"); const config = getDefaultConfig(__dirname); // Add custom extensions: config.resolver.sourceExts.push("svg"); module.exports = config;. Caching: Metro caches transformed files — --reset-cache flag clears this cache. Use when facing strange bundling issues. Production bundle: npx react-native bundle --platform ios --dev false --entry-file index.js --bundle-output ios/main.jsbundle. Bundle splitting / lazy loading: Metro supports RAM bundles and lazy module loading for faster startup on large apps.
14
What is the difference between development and production builds in React Native?
Development builds and production builds differ significantly in React Native: Development build: includes extra debugging code; JS runs unminified with source maps; JavaScript runs in Debug mode (connected to Chrome DevTools or Hermes debugger); __DEV__ is true; PropTypes warnings enabled; Redux DevTools work; Hot Refresh works; connects to Metro bundler on your computer; slower performance (JS not optimized, extra checks); larger bundle size; can use console.log() effectively. Production build: JavaScript is minified and optimized; __DEV__ is false (PropTypes checks skipped); Hermes engine compiles JS to bytecode at build time (faster startup); no connection to Metro — bundle embedded in the app binary; significantly faster performance; smaller app size; no source maps in app. Building for production: iOS: npx react-native run-ios --configuration Release or use Xcode → Product → Archive; Android: cd android && ./gradlew assembleRelease. __DEV__ global: if (__DEV__) { console.log("Debug info"); // Only runs in dev } // Common pattern: if (__DEV__) { const DevMenu = require("./DevMenu"); }. Code stripping: dead code elimination can remove __DEV__ blocks in production, reducing bundle size. Hermes (bytecode compilation): Hermes pre-compiles JS to bytecode during the build (not at runtime) — dramatically improves Time to Interactive (TTI) in production. Enabled by default for new React Native projects.
15
What is Hermes in React Native?
Hermes is an open-source JavaScript engine optimized specifically for React Native, developed by Meta. It became the default JS engine for React Native 0.70+ (on Android) and 0.71+ (on iOS). Key optimizations: (1) Ahead-of-Time (AOT) compilation: Hermes pre-compiles JavaScript to bytecode during the app build process (not at runtime). The app ships bytecode instead of raw JS source — massively improves startup time; (2) Smaller memory footprint: Hermes is designed for mobile — uses significantly less memory than V8 or JSC (JavaScriptCore); (3) Faster Time to Interactive (TTI): because JS is pre-compiled, the app starts faster — critical for user retention; (4) Garbage collection optimized for mobile — reduces GC pauses. Before Hermes: React Native used JavaScriptCore (the Safari engine). JSC had to parse and JIT-compile JS at runtime — slower startup and higher memory. Enabling Hermes: new projects have it by default. // android/app/build.gradle: project.ext.react = [ enableHermes: true, ] // ios/Podfile: use_react_native!( :hermes_enabled => true ). Hermes Debugger: works with the Hermes Debugger in React Native DevTools (not Chrome DevTools which worked with JSC). Flipper or the new React Native DevTools. Performance impact: significant improvement — apps using Hermes see 10-30% faster startup, 40-50% less memory usage in benchmarks. All new React Native projects should use Hermes.
16
What is the Image component in React Native?
The Image component displays images from local files, network URLs, or base64 data. Local images (bundled with app): import { Image } from "react-native"; <Image source={require("./assets/logo.png")} style={{ width: 100, height: 100 }} />. Metro automatically handles @2x and @3x variants (logo.png, logo@2x.png, logo@3x.png). Network images: must specify width and height (can't infer from server): <Image source={{ uri: "https://picsum.photos/200" }} style={{ width: 200, height: 200 }} />. resizeMode: how image fills the given dimensions: cover (fill, may crop), contain (fit, may letterbox), stretch (stretch to fill), repeat (tile), center (center without scaling): <Image source={...} style={{ width: 200, height: 200 }} resizeMode="cover" />. Caching: network images are cached by React Native. onLoad/onError: <Image source={{ uri }} onLoad={() => setLoading(false)} onError={() => setError(true)} onLoadStart={() => setLoading(true)} />. FastImage (react-native-fast-image): popular third-party replacement. Better caching (LRU cache), priority queuing, resizing on native side. Background images: use ImageBackground: <ImageBackground source={bg} style={{ flex: 1 }}> <Text>Overlay text</Text> </ImageBackground>. SVG: use react-native-svg — Image component doesn't natively support SVG.
17
What is TextInput in React Native?
TextInput is the component for capturing text from the user. It maps to UITextField/UITextView (iOS) and EditText (Android). Basic usage: import { TextInput } from "react-native"; const [text, setText] = useState(""); <TextInput value={text} onChangeText={setText} placeholder="Enter text..." style={styles.input} />. Key props: value — controlled value; onChangeText — callback receiving new text; placeholder — placeholder text; placeholderTextColor; secureTextEntry — password field (hides input); keyboardType: "default" | "numeric" | "email-address" | "phone-pad" | "decimal-pad" — what keyboard to show; autoCapitalize: "none" | "sentences" | "words" | "characters"; autoCorrect: {false} — disable autocorrect; multiline: {true} — multiple lines; numberOfLines — initial height for multiline; maxLength — character limit; returnKeyType: "done" | "search" | "send" | "next" — keyboard's return button label; onSubmitEditing — fires when return key is pressed; blurOnSubmit: {false} — don't blur when submitting multiline; editable: {false} — read-only. Focusing programmatically: const inputRef = useRef(null); inputRef.current.focus(); inputRef.current.blur(); <TextInput ref={inputRef} />. Styling: on iOS, TextInput has no default border. Add one via style: borderWidth: 1, borderColor: "#ccc", borderRadius: 8, padding: 12. On Android, has default underline — use underlineColorAndroid="transparent" to remove.
18
What is SafeAreaView in React Native?
SafeAreaView is a component that automatically adds padding to avoid content being obscured by device notches, status bars, home indicators, and camera cutouts. Essential for supporting modern devices (iPhone X+, Android devices with notches). Basic SafeAreaView: import { SafeAreaView } from "react-native"; export default function App() { return ( <SafeAreaView style={{ flex: 1 }}> {/* Content won't overlap the notch or home indicator */} <Text>Safe Content</Text> </SafeAreaView> ); }. react-native-safe-area-context (recommended): the community library provides more control and works better with React Navigation: import { SafeAreaProvider, SafeAreaView, useSafeAreaInsets } from "react-native-safe-area-context"; // Wrap your app: <SafeAreaProvider><App /></SafeAreaProvider> // Use in screens: <SafeAreaView edges={["top", "bottom"]}> // Control which edges get padding edges={["top"]} // Only top padding (useful for headers) </SafeAreaView>. useSafeAreaInsets hook: for finer control — apply insets manually: function Header() { const insets = useSafeAreaInsets(); return ( <View style={{ paddingTop: insets.top, backgroundColor: "blue" }}> <Text>Header</Text> </View> ); }. With React Navigation: React Navigation handles SafeArea automatically for its navigators. You only need SafeAreaView for screens with custom headers or special layouts. Expo: import { SafeAreaView } from "expo-safe-area-context" — same API as react-native-safe-area-context.
19
What is the Modal component in React Native?
The Modal component creates a full-screen overlay that renders on top of other content. Used for dialogs, alerts, pickers, full-screen images, and custom pop-up UI. Basic Modal: import { Modal, View, Text, TouchableOpacity } from "react-native"; function App() { const [visible, setVisible] = useState(false); return ( <> <TouchableOpacity onPress={() => setVisible(true)}> <Text>Open Modal</Text> </TouchableOpacity> <Modal visible={visible} transparent={true} animationType="fade" onRequestClose={() => setVisible(false)} // Android back button > <View style={styles.overlay}> <View style={styles.dialog}> <Text>Modal Content</Text> <TouchableOpacity onPress={() => setVisible(false)}> <Text>Close</Text> </TouchableOpacity> </View> </View> </Modal> </> ); }. Key props: visible — show/hide; transparent — if true, background remains visible (modal renders on transparent overlay). If false, modal covers everything with a white background; animationType: "none" | "slide" | "fade" — entrance animation; onRequestClose — required on Android for hardware back button; onShow — fires when modal shown; statusBarTranslucent (Android) — modal overlaps status bar. Semi-transparent overlay: const styles = StyleSheet.create({ overlay: { flex: 1, backgroundColor: "rgba(0,0,0,0.5)", justifyContent: "center", alignItems: "center", }, dialog: { backgroundColor: "white", borderRadius: 12, padding: 24, width: "80%" } });. For more complex modals, consider react-native-modal library with swipe-to-close, animated backdrop, etc.
20
What are React Native permissions?
Accessing sensitive device features (camera, location, contacts, notifications) requires explicit user permission. Both iOS and Android have permission systems, but they work differently. react-native-permissions is the standard library providing a unified API: import { check, request, PERMISSIONS, RESULTS } from "react-native-permissions"; // Check current status: const result = await check(PERMISSIONS.IOS.CAMERA); // "denied" | "granted" | "blocked" | "unavailable" | "limited" // Request permission: const result = await request(PERMISSIONS.IOS.CAMERA); if (result === RESULTS.GRANTED) { openCamera(); } else if (result === RESULTS.BLOCKED) { // User denied and selected "Don't ask again" // Open settings: Linking.openSettings(); }. Common permissions: PERMISSIONS.IOS.CAMERA, PERMISSIONS.IOS.PHOTO_LIBRARY, PERMISSIONS.IOS.LOCATION_WHEN_IN_USE, PERMISSIONS.IOS.MICROPHONE, PERMISSIONS.ANDROID.CAMERA, PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE, PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION. Info.plist (iOS): must add usage description strings — app will crash if missing: NSCameraUsageDescription = "We need camera access to take photos.". AndroidManifest.xml: declare permissions: <uses-permission android:name="android.permission.CAMERA" />. Runtime permissions (Android 6+): must also request at runtime. requestMultiple: await requestMultiple([PERMISSIONS.IOS.CAMERA, PERMISSIONS.IOS.MICROPHONE]). Always handle all permission states gracefully — guide users to Settings if blocked.
21
What is linking in React Native?
The Linking API allows React Native apps to interact with the outside world — opening URLs (web, email, phone, maps), handling deep links into your own app, and opening the device settings. Opening URLs: import { Linking } from "react-native"; // Open a webpage: await Linking.openURL("https://reactnative.dev"); // Make a phone call: await Linking.openURL("tel:+1234567890"); // Send an email: await Linking.openURL("mailto:support@example.com?subject=Help"); // Open maps: await Linking.openURL("https://maps.google.com/?q=New+York"); // Open app settings: await Linking.openSettings(); // Check if URL can be opened: const canOpen = await Linking.canOpenURL("fb://profile/123"); if (canOpen) { await Linking.openURL("fb://profile/123"); } else { await Linking.openURL("https://facebook.com/123"); }. Deep linking (handling incoming URLs): configure the app to respond to custom URL schemes (myapp://screen/id) or Universal Links (iOS) / App Links (Android) (https://myapp.com/screen/id): useEffect(() => { // Handle initial URL (app was closed): Linking.getInitialURL().then(url => { if (url) handleDeepLink(url); }); // Handle URL while app is open: const subscription = Linking.addEventListener("url", ({ url }) => { handleDeepLink(url); }); return () => subscription.remove(); }, []);. React Navigation handles deep linking automatically with linking config prop on NavigationContainer.
22
What is the Dimensions API in React Native?
The Dimensions API provides the width and height of the device screen and window. Essential for responsive layouts that adapt to different screen sizes. Basic usage: import { Dimensions } from "react-native"; const { width, height } = Dimensions.get("window"); // App window const { width: screenWidth } = Dimensions.get("screen"); // Physical screen (includes status bar on Android) console.log(width, height); // e.g., 390, 844 (iPhone 14). window vs screen: window — the app's usable area (excludes status bar on Android, includes safe area insets calculation); screen — the full physical display dimensions. Use window for layout calculations. Problem: Dimensions is a snapshot at the time of call — doesn't update on orientation change automatically. useWindowDimensions hook (recommended): reactive — automatically updates when orientation changes or window resizes: import { useWindowDimensions } from "react-native"; function MyComponent() { const { width, height } = useWindowDimensions(); const isLandscape = width > height; return ( <View style={{ width: isLandscape ? width / 2 : width }}> <Text>{width} x {height}</Text> </View> ); }. PixelRatio: gets the pixel density ratio of the screen: import { PixelRatio } from "react-native"; PixelRatio.get(); // 2 on iPhone Retina (2x), 3 on Plus/Pro (3x) const pixelWidth = PixelRatio.roundToNearestPixel(100); // Round to nearest physical pixel for crisp rendering. Responsive design patterns: calculate percentages: const cardWidth = width * 0.9; or use libraries like react-native-responsive-screen.
23
What is the Alert API in React Native?
The Alert API displays native platform alert dialogs — iOS alert sheets and Android dialog boxes. It provides simple yes/no confirmations and multi-button dialogs using the platform's native UI. Simple alert: import { Alert } from "react-native"; Alert.alert("Title", "Message body"); // OK button automatically. Confirm dialog: Alert.alert( "Delete Item", "Are you sure you want to delete this?", [ { text: "Cancel", style: "cancel", // styled as cancel action onPress: () => console.log("Cancelled"), }, { text: "Delete", style: "destructive", // red on iOS onPress: () => deleteItem(), }, ] );. Alert.prompt (iOS only): alert with a text input field — not available on Android: Alert.prompt( "Enter Name", "Please enter your name:", [ { text: "Cancel", style: "cancel" }, { text: "OK", onPress: name => console.log("Name:", name) } ], "plain-text", "Default Value" );. Button styles: "default" (normal), "cancel" (bold on iOS), "destructive" (red on iOS). Limitations: Alert is platform-native — appearance differs between iOS and Android; can't heavily customize the UI; for custom styled dialogs, use the Modal component or react-native-modal library. Blocking: Alert is non-blocking — the callback fires asynchronously. The JS thread continues after Alert.alert() is called.
24
What is the FlatList component and its key props?
FlatList is the standard list component for rendering large, scrollable lists efficiently. It only renders items visible on screen (virtualization). Basic FlatList: <FlatList data={users} keyExtractor={user => user.id.toString()} renderItem={({ item, index, separators }) => ( <UserCard user={item} onPress={() => navigate("UserDetail", { id: item.id })} /> )} />. Essential props: data — array of items; renderItem — function returning component for each item; keyExtractor — returns a unique key string for each item (for reconciliation). Performance props: initialNumToRender — items rendered on first render (default: 10); maxToRenderPerBatch — items rendered per batch; windowSize — virtual window size (default: 21 — 10 viewports above + current + 10 below); getItemLayout — if item height is fixed, provide this for huge performance gain: getItemLayout={(data, index) => ({ length: 60, offset: 60 * index, index })}. Pull to refresh: refreshing={isLoading} onRefresh={handleRefresh}. Infinite scroll: onEndReached={loadMore} onEndReachedThreshold={0.5} (triggers when 50% from bottom). Separators: ItemSeparatorComponent={() => <View style={styles.separator} />}. Header/Footer: ListHeaderComponent={<Header />} ListFooterComponent={<Footer />} ListEmptyComponent={<EmptyState />}. Horizontal list: horizontal={true} — scrolls left-right.
25
What is the Animated API in React Native?
The Animated API is React Native's built-in animation library that drives smooth, high-performance animations by running on the native UI thread (with useNativeDriver: true). Core concepts: (1) Animated.Value: a single animated number: const opacity = useRef(new Animated.Value(0)).current;; (2) Animated functions: create animations that update the value: // Timing (tween to a value): Animated.timing(opacity, { toValue: 1, duration: 300, easing: Easing.ease, useNativeDriver: true, }).start(); // Spring (bouncy physics): Animated.spring(scale, { toValue: 1.2, friction: 7, tension: 40, useNativeDriver: true, }).start(); // Decay (decelerate from velocity): Animated.decay(velocity, { deceleration: 0.997, useNativeDriver: true, }).start();; (3) Animated.View (and Text, Image, ScrollView): use Animated.* components to receive animated values: // Fade in animation: const opacity = useRef(new Animated.Value(0)).current; useEffect(() => { Animated.timing(opacity, { toValue: 1, duration: 500, useNativeDriver: true }).start(); }, []); return <Animated.View style={{ opacity }}><Text>Hello!</Text></Animated.View>;. useNativeDriver: true: runs animation on the native UI thread — no JS bridge involvement per frame = 60fps even when JS is busy. Only works for non-layout properties: opacity, transform (translateX, translateY, scale, rotate). Not for width, height, backgroundColor. Sequences and parallel: Animated.sequence([anim1, anim2]).start(); Animated.parallel([anim1, anim2]).start(); Animated.stagger(100, [anim1, anim2, anim3]).start();
26
How does state management work in React Native?
React Native uses the same state management patterns as React web — the same libraries work without modification. 1. useState (local state): component-level state. Best for UI state, form values, toggles: const [isLoading, setIsLoading] = useState(false);. 2. useContext (shared state): share state across component tree without prop drilling: const ThemeContext = React.createContext("light"); function App() { return ( <ThemeContext.Provider value="dark"> <Screen /> </ThemeContext.Provider> ); } function Screen() { const theme = useContext(ThemeContext); }. 3. Redux Toolkit (complex global state): for large apps with complex state: npm install @reduxjs/toolkit react-redux. Same setup as React web. Works perfectly in React Native. 4. Zustand (simpler alternative to Redux): import { create } from "zustand"; const useStore = create(set => ({ bears: 0, addBear: () => set(state => ({ bears: state.bears + 1 })) })); // In component: const { bears, addBear } = useStore();. 5. Jotai / Recoil (atomic state): atomic state management — similar to useState but shareable. 6. MobX (reactive): observable state, automatic tracking. What to use: useState for local; Context for small shared state; Zustand/Redux Toolkit for complex global state. React Query / TanStack Query for server state (caching, refetching, loading states). Most React Native apps use: useState + Context + React Query (or SWR) + Zustand/Redux Toolkit for different layers.
27
What is KeyboardAvoidingView?
KeyboardAvoidingView automatically adjusts a view's position when the software keyboard appears, preventing the keyboard from covering important content like TextInputs. Basic usage: import { KeyboardAvoidingView, Platform } from "react-native"; function LoginScreen() { return ( <KeyboardAvoidingView style={{ flex: 1 }} behavior={Platform.OS === "ios" ? "padding" : "height"} > <ScrollView> <TextInput placeholder="Email" /> <TextInput placeholder="Password" secureTextEntry /> <Button title="Login" onPress={handleLogin} /> </ScrollView> </KeyboardAvoidingView> ); }. behavior prop: "padding" (iOS recommended) — adds padding to push content up; "height" (Android recommended) — reduces view height; "position" — translates the view upward. Different behaviors work better on different platforms — the Platform.OS check is standard practice. keyboardVerticalOffset: additional offset to account for headers: keyboardVerticalOffset={Platform.OS === "ios" ? 64 : 0}. Alternatives and improvements: wrapping content in ScrollView often works better. The react-native-keyboard-aware-scroll-view library provides a more robust solution that automatically scrolls to the focused TextInput. For complex forms, it's often the better choice. Expo: KeyboardAwareScrollView from react-native-keyboard-aware-scroll-view is commonly used in Expo projects for reliable keyboard handling across both platforms.
28
What is the difference between paddingHorizontal/paddingVertical and paddingTop/Left/Right/Bottom?
React Native provides several shorthand properties for spacing that aren't available in standard CSS: Shorthand properties: // Vertical = top + bottom: paddingVertical: 16 // Same as: paddingTop: 16, paddingBottom: 16 marginVertical: 8 // Horizontal = left + right: paddingHorizontal: 20 // Same as: paddingLeft: 20, paddingRight: 20 marginHorizontal: 12. Individual sides: paddingTop: 8 paddingRight: 16 paddingBottom: 8 paddingLeft: 16. padding (all sides): padding: 16 // All four sides margin: 8 // All four sides. Priority (most specific wins): // paddingHorizontal overrides padding for left/right: padding: 20 paddingHorizontal: 0 // Result: top=20, bottom=20, left=0, right=0. Start/End (for RTL support): paddingStart: 16 // Same as paddingLeft in LTR, paddingRight in RTL paddingEnd: 16 // Same as paddingRight in LTR, paddingLeft in RTL. Use Start/End instead of Left/Right when building apps with RTL language support (Arabic, Hebrew). borderRadius shortcuts: borderRadius: 8 // All corners borderTopLeftRadius: 8 borderTopRightRadius: 8 borderBottomLeftRadius: 0 borderBottomRightRadius: 0. These are React Native-specific shorthands — not all are available in web CSS. The marginVertical and paddingHorizontal shorthands are particularly useful for reducing repetition in StyleSheet definitions.
29
What is Fast Refresh in React Native?
Fast Refresh is React Native's hot reloading mechanism that applies code changes to your running app in real-time — typically in under 1 second — without requiring a full reload or losing component state. How it works: when you save a file, Metro detects the change; sends only the changed modules to the running app; React's reconciler applies the new code while preserving component state where possible (state in hooks, etc.); if a change affects only a React component's render logic, state is preserved; if a change is outside React components (class changes, module initialization), a full reload is triggered automatically. Benefits over old Hot Reload: more reliable; handles more code change patterns; preserves state more consistently; automatic full refresh when needed. What gets preserved: useState values, useRef values, component state in general. What triggers full reload: changes to non-React files (utility functions with side effects), class components with lifecycle changes, syntax errors (then auto-recovers when fixed). Enabling/disabling: enabled by default. To force a full reload: shake the device → Reload, or press r in Metro terminal, or Cmd+R in iOS Simulator, R twice in Android emulator. State preservation caveat: if you add a new state variable or change the hook order, Fast Refresh may reset state. Changes to the component's body that affect existing state variables are preserved. Fast Refresh is specific to development — not active in production builds.
Practical knowledge for developers with hands-on experience.
01
What is the React Native New Architecture?
The New Architecture (introduced in React Native 0.68, stable in 0.76) fundamentally changes how JavaScript communicates with native code, replacing the legacy "bridge" with a more efficient system. Old Architecture problems: the bridge was asynchronous — JS and native were separated, all communication was serialized to JSON and passed asynchronously. This caused: dropped frames (bridge got congested), inability to call native code synchronously, limited native-to-JS synchronous callbacks. New Architecture components: (1) JSI (JavaScript Interface): replaces the async JSON bridge with direct synchronous calls. JS objects can hold references to C++ objects and call methods directly — like calling a native function from JS without serialization. This enables synchronous communication; (2) Fabric (new rendering engine): reimplements the rendering system in C++. UI rendering can happen on any thread, enabling synchronous layout and concurrent features (React 18 Concurrent Mode). Shadow tree is now C++ instead of Java/ObjC; (3) TurboModules: lazy loading of native modules — only loaded when first used (not all upfront at startup). Typed interface via CodeGen; (4) CodeGen: generates type-safe native code from TypeScript/Flow type annotations — eliminates type mismatches between JS and native. Benefits: faster startup (TurboModules lazy load), synchronous native calls possible via JSI, React 18 Concurrent Mode support, better performance on complex UIs. Interop layer: Old and New Architecture components can work together during migration.
02
What is React Navigation nested navigators?
Nested navigators combine multiple navigators together — for example, a Tab navigator where each tab contains its own Stack navigator. This is the standard pattern for most production apps. Common pattern — Tabs with Stacks: const HomeStack = createNativeStackNavigator(); function HomeStackNavigator() { return ( <HomeStack.Navigator> <HomeStack.Screen name="HomeMain" component={HomeScreen} /> <HomeStack.Screen name="ProductDetail" component={ProductDetailScreen} /> </HomeStack.Navigator> ); } const Tab = createBottomTabNavigator(); function TabNavigator() { return ( <Tab.Navigator> <Tab.Screen name="Home" component={HomeStackNavigator} /> <Tab.Screen name="Search" component={SearchScreen} /> <Tab.Screen name="Profile" component={ProfileScreen} /> </Tab.Navigator> ); } // Top level: Stack (auth gate) → Tabs → individual stacks const RootStack = createNativeStackNavigator(); function RootNavigator() { return ( <RootStack.Navigator> <RootStack.Screen name="Auth" component={AuthNavigator} /> <RootStack.Screen name="Main" component={TabNavigator} /> </RootStack.Navigator> ); }. Navigating to nested screen: navigation.navigate("Home", { screen: "ProductDetail", params: { id: 123 } });. Tab bar visibility: to hide the tab bar on certain screens, keep those screens in a Stack navigator outside the Tab navigator, not inside a Tab's Stack. Drawer + Tabs: common pattern for apps with side drawer and tab navigation.
03
How do you handle network requests in React Native?
React Native provides the Fetch API (same as browser) and you can use any JavaScript HTTP library. Fetch API (built-in): async function fetchUsers() { try { const response = await fetch("https://api.example.com/users", { method: "GET", headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json", }, }); if (!response.ok) { throw new Error(`HTTP error: ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.error("Fetch error:", error); throw error; } } // POST: const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: "Alice", email: "alice@example.com" }), });. Axios (popular library): import axios from "axios"; const api = axios.create({ baseURL: "https://api.example.com", timeout: 10000, headers: { "Content-Type": "application/json" }, }); // Interceptors for auth headers: api.interceptors.request.use(config => { config.headers.Authorization = `Bearer ${getToken()}`; return config; }); const { data } = await api.get("/users"); const { data: user } = await api.post("/users", { name: "Alice" });. React Query (TanStack Query) for server state: import { useQuery, useMutation } from "@tanstack/react-query"; const { data, isLoading, error, refetch } = useQuery({ queryKey: ["users"], queryFn: fetchUsers, staleTime: 5 * 60 * 1000, }); const mutation = useMutation({ mutationFn: createUser, onSuccess: () => queryClient.invalidateQueries({ queryKey: ["users"] }) });. React Query handles caching, background refresh, retry, and loading/error states automatically — highly recommended for production apps.
04
What are Native Modules in React Native?
Native Modules allow JavaScript to call native platform code (Swift/Objective-C on iOS, Kotlin/Java on Android). Used when React Native doesn't provide a built-in API for a device feature or when you need a performance-critical native implementation. When to use native modules: accessing hardware (Bluetooth, NFC), integrating third-party SDKs (analytics, payment SDKs), CPU-intensive operations (image processing, encryption), features not yet in React Native core. Old Architecture native module (iOS — Objective-C): // MyModule.h: @interface MyModule : NSObject <RCTBridgeModule> @end // MyModule.m: @implementation MyModule RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(greet:(NSString *)name resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { NSString *greeting = [NSString stringWithFormat:@"Hello, %@!", name]; resolve(greeting); } @end // JavaScript: import { NativeModules } from "react-native"; const { MyModule } = NativeModules; const greeting = await MyModule.greet("Alice");. New Architecture TurboModule: uses JSI for synchronous calls and TypeScript specifications for type safety. Community modules: thousands of pre-built native modules on npm — react-native-camera, react-native-maps, react-native-bluetooth, etc. Always check before writing your own. Expo modules API: Expo provides a cleaner API for writing native modules with Swift/Kotlin, strongly typed, works with both old and new architecture.
05
What is the difference between react-native-reanimated and the Animated API?
Both animate UI in React Native but with very different approaches and performance characteristics: Built-in Animated API: animations defined in JavaScript, values communicated to native via the bridge (or JSI); useNativeDriver: true moves animation execution to the native thread for supported properties; limitations: only opacity and transform work with useNativeDriver; interpolations, calculations happen in JS; complex gesture-driven animations cause frame drops since gesture events cross the bridge; useNativeDriver: false runs EVERYTHING in JS — very slow for complex animations. react-native-reanimated (v2/v3): animations are defined using "worklets" — special JS functions that run on the UI thread (native side). The entire animation logic runs natively — zero bridge communication during animation. Enables truly native 60fps+ animations for ANY property including layout (width, height, backgroundColor): import Animated, { useSharedValue, useAnimatedStyle, withTiming, withSpring } from "react-native-reanimated"; function AnimatedBox() { const width = useSharedValue(100); const animatedStyle = useAnimatedStyle(() => ({ width: width.value, backgroundColor: width.value > 150 ? "red" : "blue", })); return ( <Animated.View style={[styles.box, animatedStyle]} /> ); }. react-native-gesture-handler + reanimated: gestures processed natively, animations respond natively — perfect for swipeable cards, bottom sheets, interactive animations. Used by react-native-bottom-sheet, Swipeable components, etc. Summary: use reanimated for any production animation, especially gesture-driven. Use built-in Animated only for simple, static animations where simplicity matters more.
06
What is the React Native bridge and how does it work?
The bridge was the communication mechanism in the old React Native architecture between the JavaScript thread and native code. Understanding it explains many performance characteristics and limitations. Thread model (old architecture): (1) JS Thread: runs your React component code, business logic, state updates. Single-threaded JavaScript; (2) Native/UI Thread: renders native views, handles touch events, runs native animations; (3) Shadow Thread: calculates layout using Yoga (Flexbox engine) — translates React component trees to native layout; (4) Background Thread(s): networking, images, etc. How the bridge worked: all communication between JS and native was serialized to JSON and passed asynchronously across the bridge. JS calls a native method → JSON message queued → native thread processes → result JSON queued back → JS processes result. This was the biggest performance bottleneck. Problems with the bridge: serialization overhead (JSON encode/decode every message); asynchronous only (can't get synchronous values from native); bridge could become congested under heavy load; "dropped frames" when bridge was overwhelmed. New Architecture solution (JSI): JavaScript Interface allows JS objects to directly reference C++ objects. JS can call native methods synchronously. No JSON serialization. Direct function calls. Example: JS reads a scroll position from native synchronously via JSI — not possible with the old bridge. Bridge vs JSI timing: bridge ≈ 1-10ms for a round trip; JSI synchronous call ≈ microseconds. This is why the new architecture is a fundamental improvement for complex interactive UIs.
07
What is react-native-gesture-handler?
react-native-gesture-handler replaces React Native's built-in touch system with a native gesture recognition system. Built-in touch events go through the JS bridge on every touch — slow. Gesture handler processes gestures on the native thread for buttery-smooth interactions. Installation: npm install react-native-gesture-handler. Wrap root component: import { GestureHandlerRootView } from "react-native-gesture-handler"; export default function App() { return ( <GestureHandlerRootView style={{ flex: 1 }}> <Navigation /> </GestureHandlerRootView> ); }. RNGH v2 API (modern): import { Gesture, GestureDetector } from "react-native-gesture-handler"; import Animated, { useSharedValue, useAnimatedStyle, withSpring } from "react-native-reanimated"; function DraggableBox() { const offsetX = useSharedValue(0); const offsetY = useSharedValue(0); const pan = Gesture.Pan() .onChange(event => { offsetX.value += event.changeX; offsetY.value += event.changeY; }) .onEnd(() => { offsetX.value = withSpring(0); offsetY.value = withSpring(0); }); const animatedStyle = useAnimatedStyle(() => ({ transform: [{ translateX: offsetX.value }, { translateY: offsetY.value }] })); return ( <GestureDetector gesture={pan}> <Animated.View style={[styles.box, animatedStyle]} /> </GestureDetector> ); }. Other gestures: Tap, LongPress, Pinch (zoom), Rotation, Fling, simultaneous gestures. Used by: React Navigation (swipe back), react-native-bottom-sheet, react-native-draggable-flatlist.
08
What is Expo Router?
Expo Router is a file-based routing system for React Native and web (built on top of React Navigation). Files in the app/ directory automatically become routes — exactly like Next.js for React Native. Directory structure → routes: app/ _layout.tsx // Root layout (NavigationContainer equivalent) index.tsx // "/" route -- home (tabs)/(home)/index.tsx // Tab: home (tabs)/(profile)/index.tsx // Tab: profile users/ [id].tsx // Dynamic route: /users/123 profile.tsx // /profile _layout.tsx // Nested layout. Special files: _layout.tsx — defines layout for a directory (Stack, Tabs, Drawer). index.tsx — matches the directory's root route. +not-found.tsx — 404 page. (groupName)/ — route group (doesn't affect URL). Navigation: import { Link, useRouter, useLocalSearchParams } from "expo-router"; // Declarative: <Link href="/users/123">View User</Link> <Link href={{ pathname: "/users/[id]", params: { id: "123" }}}> <Text>User Profile</Text> </Link> // Programmatic: const router = useRouter(); router.push("/home"); router.replace("/login"); router.back(); // Params: const { id } = useLocalSearchParams();. Tab layout example: // app/(tabs)/_layout.tsx: export default function TabsLayout() { return ( <Tabs> <Tabs.Screen name="index" options={{ title: "Home", tabBarIcon: ({ color }) => <Icon name="home" color={color} /> }} /> </Tabs> ); }. Deep linking: automatic — URLs match the file structure. Works on web natively. Typed routes (Expo SDK 50+): TypeScript knows all valid routes — compile-time navigation type safety.
09
What is react-native-maps?
react-native-maps integrates native Google Maps (Android) and Apple Maps/Google Maps (iOS) into React Native apps. It renders real native map views for the best performance and UX. Installation: npm install react-native-maps. Google Maps requires a Google Maps API key configured in AndroidManifest.xml. Basic map: import MapView, { Marker, Callout, Circle, Polyline } from "react-native-maps"; <MapView style={{ flex: 1 }} initialRegion={{ latitude: 37.78825, longitude: -122.4324, latitudeDelta: 0.0922, longitudeDelta: 0.0421, }} mapType="standard" // "satellite", "hybrid", "terrain" showsUserLocation={true} showsMyLocationButton={true} onPress={event => console.log(event.nativeEvent.coordinate)} onRegionChangeComplete={region => console.log(region)} > <Marker coordinate={{ latitude: 37.78825, longitude: -122.4324 }} title="My Location" description="I am here" onPress={() => {}} > {/* Custom marker: */} <View style={styles.customMarker} /> </Marker> <Circle center={{ latitude: 37.78825, longitude: -122.4324 }} radius={500} fillColor="rgba(0,100,255,0.2)" strokeColor="rgba(0,100,255,0.5)" /> </MapView>. Camera control: const mapRef = useRef(null); mapRef.current.animateToRegion(newRegion, 1000); // Smooth animation mapRef.current.fitToCoordinates(coords, { edgePadding: { top: 50, right: 50, bottom: 50, left: 50 } });. Expo alternative: expo-location for location, and react-native-maps works in bare workflow. Expo Maps is a newer alternative.
10
What is the difference between Expo Go and a custom development build?
These two development options differ in what native capabilities they support: Expo Go: a pre-built app downloaded from the App Store/Play Store. Contains a fixed set of pre-compiled native modules (the Expo SDK). You point it at your Metro bundler and run your JS code inside Expo Go. Pros: instant setup (no Xcode/Android Studio needed), fast to start, works on physical devices easily. Cons: limited to Expo SDK's built-in modules — can't use custom native modules or third-party packages with native code not in the SDK. Custom Development Build (using EAS Build): a development version of YOUR app with your own native code. Built using eas build --profile development. Supports any native module (react-native-vision-camera, react-native-ble-plx, custom modules, etc.). Includes Expo Dev Client — same DX as Expo Go but with your native code. Pros: full native access, installable as a real app, same workflow as production build. Cons: requires initial build time (~10-20 minutes), needs EAS account (or local build). When to use each: Expo Go — learning, prototyping, apps that don't need custom native code; Development Build — production apps, when you need any native library not in Expo SDK, when you're beyond the prototype phase. Development profile in eas.json: { "build": { "development": { "developmentClient": true, "distribution": "internal" } } }. Most production Expo apps: use custom development builds. Expo Go is primarily for learning and rapid prototyping.
11
How do you implement authentication in React Native?
Authentication in React Native involves token management, secure storage, and navigation guards. Common pattern: // 1. AuthContext.tsx: const AuthContext = createContext(null); export function AuthProvider({ children }) { const [token, setToken] = useState(null); const [isLoading, setIsLoading] = useState(true); useEffect(() => { // Check for stored token on app start: const loadToken = async () => { const storedToken = await SecureStore.getItemAsync("auth_token"); if (storedToken) setToken(storedToken); setIsLoading(false); }; loadToken(); }, []); const login = async (credentials) => { const { token } = await api.login(credentials); await SecureStore.setItemAsync("auth_token", token); setToken(token); }; const logout = async () => { await SecureStore.deleteItemAsync("auth_token"); setToken(null); }; return ( <AuthContext.Provider value={{ token, login, logout, isLoading }}> {children} </AuthContext.Provider> ); } // 2. Navigation guard: function RootNavigator() { const { token, isLoading } = useContext(AuthContext); if (isLoading) return <SplashScreen />; return token ? <AppNavigator /> : <AuthNavigator />; }. Secure token storage: Use expo-secure-store or react-native-keychain — not AsyncStorage (unencrypted). Social auth: expo-auth-session (OAuth/OIDC), @react-native-google-signin/google-signin, Facebook SDK. Clerk/Auth0/Supabase: third-party auth services with React Native SDKs — handle token management, refresh, biometric auth. Biometric auth: expo-local-authentication for Face ID / Touch ID / Fingerprint unlock.
12
What is performance optimization in React Native?
React Native performance optimization covers multiple layers: 1. Avoid unnecessary re-renders: // React.memo -- prevent re-render if props unchanged: const UserCard = React.memo(({ user, onPress }) => { ... }); // useCallback -- stable function reference: const handlePress = useCallback(() => navigate(user.id), [user.id]); // useMemo -- expensive computation: const sortedUsers = useMemo(() => [...users].sort(), [users]);. 2. FlatList optimization: <FlatList getItemLayout={(_, index) => ({ length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index })} // Fixed height: huge perf win initialNumToRender={10} maxToRenderPerBatch={10} windowSize={5} removeClippedSubviews={true} keyExtractor={item => item.id} />. 3. Image optimization: use FastImage (react-native-fast-image) for caching; resize images to display size before showing; use WebP format; lazy load off-screen images. 4. JS thread offloading: heavy computation → react-native-reanimated worklets (UI thread); background tasks → react-native-background-fetch; use InteractionManager for non-urgent work. 5. Bundle size: enable Hermes; use dynamic imports for code splitting; tree-shake unused code; analyze with --bundle-analyze. 6. Inline requires: defer module loading until actually needed. 7. Avoid overdraw: don't use unnecessary backgroundColor on views that overlap; transparent backgrounds are cheaper. 8. Profiling: Flipper + React DevTools Profiler; use Perf Monitor (shake device → Show Perf Monitor); measure JS FPS and UI FPS; look for JS thread FPS drops (JS doing too much work per frame).
13
What is CodePush (App Center) and OTA updates?
Over-the-Air (OTA) updates allow pushing JavaScript and asset changes to users' devices without going through the App Store/Play Store review process. React Native's architecture enables this because the app's behavior is determined by the JavaScript bundle — native code stays the same, only JS updates. How OTA works: you upload a new JS bundle to a hosting service; on app startup, the app checks for updates; downloads the new bundle in the background; applies the update on next app restart. EAS Update (Expo's OTA service): the modern solution for Expo projects: // Publish update: npx eas-cli update --branch production --message "Fix crash" // In app code: import * as Updates from "expo-updates"; async function checkForUpdate() { const update = await Updates.checkForUpdateAsync(); if (update.isAvailable) { await Updates.fetchUpdateAsync(); await Updates.reloadAsync(); // Apply immediately } }. Microsoft App Center CodePush: the original OTA solution, works with both Expo and bare React Native: import codePush from "react-native-code-push"; const App = codePush({ checkFrequency: codePush.CheckFrequency.ON_APP_START, installMode: codePush.InstallMode.NEXT_RESTART })(RootComponent);. Limitations: OTA can only update JavaScript and assets (images, fonts). Cannot update native code — those still require App Store releases. Apple's guidelines: OTA updates must not fundamentally change app behavior or add new features (bug fixes and minor improvements are generally fine). Channels/Branches: different update channels for production, staging, beta testers.
14
What is Deep Linking in React Native?
Deep linking allows external URLs to open specific screens in your app — like clicking a link in an email and having the app open to the relevant screen. Two types: Custom URL Schemes (myapp://screen/id): your app registers a custom protocol. Works on any device but shows an alert on iOS if app not installed. Easier to implement. Universal Links (iOS) / App Links (Android) (https://yourdomain.com/...): uses real HTTPS URLs. If app is installed, opens the app; if not, opens the browser. Seamless UX, requires server-side configuration (apple-app-site-association file / assetlinks.json). Configuration for custom scheme: iOS Info.plist: <key>CFBundleURLTypes</key> <array><dict> <key>CFBundleURLSchemes</key> <array><string>myapp</string></array> </dict></array>. Android AndroidManifest.xml: <intent-filter> <action android:name="android.intent.action.VIEW" /> <data android:scheme="myapp" /> </intent-filter>. React Navigation deep linking config: const linking = { prefixes: ["myapp://", "https://myapp.com"], config: { screens: { Home: "", Profile: "user/:id", Settings: "settings" } } }; <NavigationContainer linking={linking}>. Expo Router: deep linking is automatic — URL structure matches file structure. Universal links require Expo config and server file. Testing: npx uri-scheme open myapp://user/123 --ios or adb shell am start -W -a android.intent.action.VIEW -d "myapp://user/123".
15
What is the useEffect hook and common patterns in React Native?
useEffect in React Native follows the same rules as React web but with some mobile-specific patterns: Data fetching on mount: useEffect(() => { let isMounted = true; async function fetchData() { try { setLoading(true); const data = await api.getUsers(); if (isMounted) setUsers(data); } catch (err) { if (isMounted) setError(err.message); } finally { if (isMounted) setLoading(false); } } fetchData(); return () => { isMounted = false; }; // Cleanup -- prevent setState on unmounted }, []);. Subscribing to app state changes: useEffect(() => { const subscription = AppState.addEventListener("change", nextAppState => { if (nextAppState === "active") { // App came to foreground -- refresh data fetchData(); } }); return () => subscription.remove(); }, []);. Screen focus (React Navigation): import { useFocusEffect } from "@react-navigation/native"; useFocusEffect( useCallback(() => { // Runs when screen is focused fetchData(); return () => { // Cleanup when screen blurs }; }, []) );. Keyboard listeners: useEffect(() => { const showSub = Keyboard.addListener("keyboardDidShow", handleShow); const hideSub = Keyboard.addListener("keyboardDidHide", handleHide); return () => { showSub.remove(); hideSub.remove(); }; }, []);. Hardware back button (Android): useEffect(() => { const backHandler = BackHandler.addEventListener("hardwareBackPress", () => { if (canGoBack) { goBack(); return true; // Prevent default } return false; // Default behavior }); return () => backHandler.remove(); }, [canGoBack]);.
16
What is Flipper in React Native?
Flipper is a desktop debugging platform for mobile apps (iOS, Android, React Native) developed by Meta. It provides a visual interface for inspecting, debugging, and profiling your React Native app. Core features: (1) Network inspector: see all network requests with URL, method, headers, request/response body, status codes, timing; (2) React DevTools: inspect component tree, props, state, hooks — integrated React DevTools; (3) Layout inspector: inspect view hierarchy, dimensions, styles — like Chrome DevTools Elements panel for native views; (4) Crash reporter: symbolicated crash reports; (5) Shared Preferences / AsyncStorage viewer — inspect stored values; (6) SQLite viewer; (7) Logs viewer — device logs; (8) Hermes Debugger — JS debugging when using Hermes engine. Setup: Flipper desktop app + Flipper SDK in React Native (included by default in recent RN versions). Status of Flipper (2024): Meta announced Flipper will be removed from React Native default setup (React Native 0.74+). The New Architecture uses new DevTools. React Native DevTools (replacing Flipper): React Native 0.73+ ships with a new DevTools experience based on Chrome DevTools Protocol. Open via j in Metro console or npx react-native start. Provides: JS debugging, network requests, profiling. For existing projects: Flipper still works and is actively maintained by the community even as Meta moves away from it.
17
What are background tasks in React Native?
Background tasks allow React Native apps to execute code when the app is not in the foreground. Mobile OSes heavily restrict background execution for battery life. Types of background work: (1) Background fetch (periodic): OS wakes app periodically to fetch new data. Not real-time — typically 15 minutes minimum interval: npm install react-native-background-fetch import BackgroundFetch from "react-native-background-fetch"; BackgroundFetch.configure({ minimumFetchInterval: 15 }, async taskId => { await syncData(); BackgroundFetch.finish(taskId); }, taskId => { BackgroundFetch.finish(taskId); });; (2) Background notifications: push notifications can include data payload and trigger background processing when received; (3) Background download/upload: iOS allows background URLSession for transfers that continue when app is backgrounded. Android similar with WorkManager; (4) Geofencing and location: background location updates (requires special permission justification); (5) React Native Headless JS (Android): run JS code in background when app is not running — for GCM background messages. AppState API: import { AppState } from "react-native"; const subscription = AppState.addEventListener("change", state => { // "active", "background", "inactive" (iOS only) if (state === "background") saveState(); if (state === "active") refreshData(); });. Limitations: iOS is very restrictive — background execution is limited to ~30 seconds for most task types. Android is more permissive but still has Doze mode and App Standby restrictions. Always test background behavior on real devices.
18
What is react-native-reanimated Shared Values and Worklets?
React Native Reanimated v2/v3 introduces two fundamental concepts that enable true UI-thread animations: Shared Values: a reactive value that can be shared between the JavaScript thread and the UI thread. Mutations to shared values automatically update animations on the UI thread without going through the bridge. import { useSharedValue, withTiming, withSpring } from "react-native-reanimated"; function Component() { const opacity = useSharedValue(1); // Initial value const scale = useSharedValue(1); function handlePress() { // These run on UI thread -- 60fps guaranteed: opacity.value = withTiming(0, { duration: 300 }); scale.value = withSpring(0.8); } }. Worklets: JavaScript functions that can be "transferred" to and executed on the UI thread. Marked with the "worklet" directive. All of Reanimated's animation functions (withTiming, withSpring, etc.) are worklets: // This function runs on the UI thread: function myAnimation() { "worklet"; return withSpring(1, { damping: 10 }); } // useAnimatedStyle runs on UI thread: const animatedStyle = useAnimatedStyle(() => { "worklet"; // Implicit in useAnimatedStyle return { opacity: opacity.value, // Reads shared value on UI thread transform: [{ scale: scale.value }], }; });. Why this matters: without Reanimated, a gesture event → JS thread → calculate animation → bridge → native UI update. With Reanimated: gesture event → UI thread worklet → update shared value → UI thread animation — entirely on the UI thread at 60fps even if JS is blocked. Animated.View: use Reanimated's Animated.View: import Animated from "react-native-reanimated"; <Animated.View style={animatedStyle} />.
19
What is the Context API pattern for global state in React Native?
The Context API is React's built-in solution for sharing state across the component tree without prop drilling. It's commonly used in React Native for: app theme, user authentication, language/locale, cart state. Complete auth context example: // contexts/AuthContext.tsx: interface AuthContextType { user: User | null; login: (creds: Credentials) => Promise<void>; logout: () => Promise<void>; isLoading: boolean; } const AuthContext = createContext<AuthContextType>(null!); export function AuthProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState<User | null>(null); const [isLoading, setIsLoading] = useState(true); const login = async (creds: Credentials) => { const userData = await api.login(creds); await SecureStore.setItemAsync("token", userData.token); setUser(userData.user); }; const logout = async () => { await SecureStore.deleteItemAsync("token"); setUser(null); }; return ( <AuthContext.Provider value={{ user, login, logout, isLoading }}> {children} </AuthContext.Provider> ); } export const useAuth = () => useContext(AuthContext); // Usage in any component: function ProfileScreen() { const { user, logout } = useAuth(); return ( <View> <Text>{user?.name}</Text> <Button title="Logout" onPress={logout} /> </View> ); }. Performance: every context consumer re-renders when context value changes. Split contexts by update frequency — separate frequently-updating state (user location) from rarely-updating (theme). Or use context + useReducer for complex state with memoization.
Deep expertise questions for senior and lead roles.
01
How does the React Native New Architecture improve performance?
The New Architecture (stable in RN 0.76) addresses the root causes of the old architecture's performance limitations: JSI (JavaScript Interface) — synchronous native calls: the old bridge was always async — calling native code, getting a result, and continuing took at minimum one "tick" (often 1-10ms). With JSI, JavaScript can call native C++ functions synchronously — like calling a regular JavaScript function: // Old (async bridge): NativeModules.Camera.getDeviceOrientation() .then(orientation => { /* delayed */ }) // New (JSI -- synchronous): const orientation = global.getCameraOrientation(); // Instant!. Fabric (new renderer): the rendering pipeline is now implemented in C++ and can run on the JS thread, main thread, or a background thread concurrently. Shadow tree (layout calculation) is also C++. This enables: synchronous layout measurements, concurrent React features (transitions, Suspense in rendering), faster first render (no back-and-forth between JS and native for initial layout). TurboModules: old architecture loaded ALL native modules at startup (even unused ones). TurboModules load lazily — only when first accessed. Plus, they're typed via CodeGen — no runtime type checking. CodeGen: generates type-safe C++ glue code from TypeScript specs. Eliminates entire classes of type mismatch bugs between JS and native. Faster because the type bridge code is generated at build time. React 18 Concurrent Mode: Fabric enables React's Concurrent features — startTransition, useDeferredValue, Suspense for data fetching. The renderer can interrupt non-urgent renders to stay responsive. Real-world impact: faster app startup (TurboModules), smoother animations when combined with Reanimated, better list performance, React 18 features.
02
What is react-native-vision-camera?
react-native-vision-camera (formerly react-native-camera) is the most powerful camera library for React Native. It provides direct access to camera hardware with frame processor plugins for real-time computer vision. Basic camera view: import { Camera, useCameraPermission, useCameraDevice } from "react-native-vision-camera"; function CameraScreen() { const { hasPermission, requestPermission } = useCameraPermission(); const device = useCameraDevice("back"); const camera = useRef(null); useEffect(() => { if (!hasPermission) requestPermission(); }, []); const takePhoto = async () => { const photo = await camera.current.takePhoto({ flash: "on", }); console.log(photo.path); }; if (!device) return <Text>No camera</Text>; return ( <Camera ref={camera} style={StyleSheet.absoluteFill} device={device} isActive={true} photo={true} video={true} /> ); }. Frame Processors (the unique powerful feature): run Worklets (JS functions on UI thread) on every camera frame in real-time — for AR, barcode scanning, face detection, object detection: import { useFrameProcessor } from "react-native-vision-camera"; import { scanBarcodes } from "vision-camera-code-scanner"; const frameProcessor = useFrameProcessor(frame => { "worklet"; const barcodes = scanBarcodes(frame, [BarcodeFormat.QR_CODE]); // Runs at 60fps on UI thread if (barcodes.length > 0) { runOnJS(handleBarcode)(barcodes[0]); } }, []);. Performance: frame processors run in a Worklet on the UI thread — real-time 60fps processing without touching the JS thread. Plugins are native C++/Swift/Kotlin for maximum performance. v4 (new): adds Skia integration for drawing overlays directly on camera frames.
03
What is WatermelonDB for React Native?
WatermelonDB is a high-performance, reactive local database for React Native (and web) that uses SQLite under the hood. It's designed for large, complex data sets where performance matters — syncing thousands of records, complex queries, offline-first apps. Why not just AsyncStorage or MMKV? AsyncStorage/MMKV are key-value stores — simple, flat data. WatermelonDB has relational data, indexes, complex queries, and reactive updates. Core concepts: // 1. Define schema: const schema = appSchema({ version: 1, tables: [ tableSchema({ name: "posts", columns: [ { name: "title", type: "string" }, { name: "body", type: "string" }, { name: "user_id", type: "string", isIndexed: true }, { name: "created_at", type: "number" }, ] }), ] }); // 2. Define model: class Post extends Model { static table = "posts"; @field("title") title; @field("body") body; @relation("users", "user_id") user; } // 3. Query with reactivity: const PostsList = withObservables([""], ({ database }) => ({ posts: database.get("posts").query( Q.where("user_id", userId), Q.sortBy("created_at", Q.desc) ).observe(), }))(PostsListUI); // 4. Write in batch (atomic, fast): await database.write(async () => { const post = await database.get("posts").create(post => { post.title = "New Post"; }); });. Sync: WatermelonDB has a built-in sync protocol — sync local changes to your server, pull server changes. Conflict resolution included. Performance: reads are O(1) via indexes; writes are batched; SQLite is far faster than JSON storage for large datasets.
04
What is react-native-skia?
@shopify/react-native-skia brings the Skia graphics engine (used by Flutter and Chrome) to React Native, enabling high-performance 2D graphics, custom shaders, and complex visual effects directly in React Native. Why Skia? Native drawing APIs (Canvas on Android, Core Graphics on iOS) are different and complex. Skia provides a unified, powerful 2D graphics API that runs on the UI thread via JSI — rendering at 60fps without touching the JS thread. Basic Skia drawing: import { Canvas, Circle, Group, LinearGradient, Path, Rect, Text, useFont } from "@shopify/react-native-skia"; function SkiaDemo() { return ( <Canvas style={{ flex: 1 }}> <Rect x={0} y={0} width={256} height={256}> <LinearGradient start={{ x: 0, y: 0 }} end={{ x: 256, y: 256 }} colors={["#00ff00", "#0000ff"]} /> </Rect> <Circle cx={128} cy={128} r={64} color="red" opacity={0.8} /> </Canvas> ); }. Animations with Skia: Skia values integrate with react-native-reanimated — animations drive Skia drawing on the UI thread: const progress = useSharedValue(0); // Drive animation from gestures or timing const cx = useDerivedValue(() => 128 + 64 * Math.cos(progress.value * 2 * Math.PI)); <Circle cx={cx} cy={cy} r={10} color="white" />. Shader (fragment shader) support: GLSL/SkSL shaders for complex visual effects — gradients, blur, displacement maps, procedural textures. Image filters: blur, color matrix, drop shadow — applied to any Skia content. Used by: Shopify (their design team built it), complex data visualizations, games, creative apps, photo editors in React Native.
05
What is MMKV and how does it compare to AsyncStorage?
react-native-mmkv is a high-performance key-value storage library based on WeChat's MMKV framework (Memory-Mapped Key-Value). It's synchronous, extremely fast, and supports encryption — making it a superior replacement for AsyncStorage in most cases. Why MMKV over AsyncStorage: MMKV reads and writes synchronously (no async/await); uses memory-mapped files — data written to memory, OS maps to disk; 30-100x faster than AsyncStorage in benchmarks; supports encryption (AES-256); no size limits per key. Installation: npm install react-native-mmkv. Usage: import { MMKV } from "react-native-mmkv"; const storage = new MMKV(); // Synchronous reads and writes: storage.set("user.name", "Alice"); storage.set("user.age", 30); storage.set("user.premium", true); const name = storage.getString("user.name"); // "Alice" const age = storage.getNumber("user.age"); // 30 const isPremium = storage.getBoolean("user.premium"); // true // Delete: storage.delete("user.name"); // Check existence: storage.contains("user.name"); // Objects -- must JSON encode: storage.set("user.profile", JSON.stringify(profile)); const profile = JSON.parse(storage.getString("user.profile") ?? "{}"); // Clear all: storage.clearAll(); // Encrypted storage: const secureStorage = new MMKV({ id: "secure-storage", encryptionKey: "my-encryption-key-32-chars-long" });. With Zustand (popular pattern): const useStore = create(persist(storeDefinition, { name: "app-store", storage: createJSONStorage(() => zustandMMKVStorage), }));. When to use AsyncStorage: when synchronous reads are problematic (large stored values blocking JS thread). Use MMKV for almost everything else.
06
What is the Reanimated layout animation system?
React Native Reanimated v2/v3's Layout Animations allow you to animate components when they mount, unmount, and when their layout changes — with minimal code. No need to manually coordinate animations with state changes. Entering animations: import Animated, { FadeIn, FadeOut, SlideInLeft, BounceIn, ZoomIn } from "react-native-reanimated"; // Component fades in when it mounts: <Animated.View entering={FadeIn.duration(500)}> <Text>I fade in!</Text> </Animated.View> // Bounce in with custom settings: <Animated.View entering={BounceIn.delay(200).springify().damping(15)}>. Exiting animations: <Animated.View exiting={FadeOut.duration(300)}> <Text>I fade out when removed</Text> </Animated.View>. Layout transitions (when position/size changes): // When items reorder, they animate smoothly: <Animated.View layout={LinearTransition}> {/* This view smoothly transitions to its new position */} </Animated.View>. List animation (staggered): function AnimatedList({ items }) { return items.map((item, index) => ( <Animated.View key={item.id} entering={FadeInUp.delay(index * 100).springify()} exiting={FadeOutDown} > <ItemCard item={item} /> </Animated.View> )); }. Custom animations: const MyEntering = new Keyframe({ 0: { opacity: 0, transform: [{ scale: 0 }] }, 100: { opacity: 1, transform: [{ scale: 1 }], easing: Easing.bounce } }); <Animated.View entering={MyEntering}>. All layout animations run on the UI thread — 60fps without blocking JS. Works correctly with FlatList items, conditional rendering, tab changes.
07
What is the React Native testing strategy?
Testing in React Native uses similar tools to React web testing but with some mobile-specific considerations: Unit tests (Jest): test utility functions, business logic, reducers, hooks in isolation — no React Native rendering needed: // jest.config.js: preset: "react-native" // Mocks native modules automatically test("calculateTotal", () => { expect(calculateTotal([10, 20, 30])).toBe(60); });. Component tests (React Native Testing Library): import { render, fireEvent, screen } from "@testing-library/react-native"; test("button increments count", () => { render(<Counter />); fireEvent.press(screen.getByText("Increment")); expect(screen.getByText("Count: 1")).toBeTruthy(); }); // Mock hooks: jest.mock("@react-navigation/native", () => ({ useNavigation: () => ({ navigate: jest.fn() }), }));. Mocking native modules: // jest.setup.js: jest.mock("@react-native-async-storage/async-storage", () => require("@react-native-async-storage/async-storage/jest/async-storage-mock")); jest.mock("react-native-mmkv", () => ({ MMKV: jest.fn().mockImplementation(() => ({ set: jest.fn(), getString: jest.fn(), getBoolean: jest.fn(), })) }));. E2E tests (Detox): full end-to-end testing on iOS Simulator / Android Emulator. Actually interacts with the running app: describe("Login flow", () => { it("logs in with valid credentials", async () => { await element(by.id("email-input")).typeText("user@test.com"); await element(by.id("password-input")).typeText("password"); await element(by.id("login-button")).tap(); await expect(element(by.id("home-screen"))).toBeVisible(); }); });. Testing strategy: many unit tests (fast), fewer component tests, few E2E tests (slow). Mock all native modules in Jest. Use MSW (Mock Service Worker) or jest mocks for network requests. Snapshot tests for UI regression detection.
08
What is react-native-svg and when do you use it?
react-native-svg brings SVG rendering to React Native. The Image component can't display SVG files natively — react-native-svg provides SVG primitives that render using native drawing APIs. Installation: npm install react-native-svg. Basic SVG usage: import Svg, { Circle, Rect, Path, Text, G, Defs, LinearGradient, Stop } from "react-native-svg"; function Logo() { return ( <Svg width={100} height={100} viewBox="0 0 100 100"> <Defs> <LinearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%"> <Stop offset="0%" stopColor="#667eea" /> <Stop offset="100%" stopColor="#764ba2" /> </LinearGradient> </Defs> <Rect width={100} height={100} fill="url(#gradient)" rx={20} /> <Circle cx={50} cy={50} r={30} fill="white" opacity={0.9} /> <Path d="M30,50 L50,30 L70,50 L50,70 Z" fill="#667eea" /> </Svg> ); }. SVG files: import .svg files as components with react-native-svg-transformer: // metro.config.js: module.exports = { transformer: { babelTransformerPath: require.resolve("react-native-svg-transformer") }, resolver: { assetExts: assetExts.filter(ext => ext !== "svg"), sourceExts: [...sourceExts, "svg"] } }; // Now import SVG as component: import Logo from "./assets/logo.svg"; <Logo width={100} height={100} />. Animated SVGs: combine with react-native-reanimated for animated SVG paths (loading indicators, charts, icon animations): const AnimatedCircle = Animated.createAnimatedComponent(Circle); <AnimatedCircle r={radius} />. Charts: victory-native and react-native-gifted-charts use react-native-svg for cross-platform chart rendering.
09
What is the performance of FlatList and how do you optimize it for large datasets?
FlatList's performance for large datasets depends on correct configuration. With wrong settings, a 10,000-item list scrolls poorly; with correct settings, it stays buttery smooth. The rendering window: FlatList renders items in a "window" around the current scroll position. Items outside the window are unmounted (or kept but invisible — controlled by removeClippedSubviews). The window size is configurable. Critical optimization — fixed item heights: // Without this, FlatList doesn't know item heights before rendering // Must measure each item to calculate scroll position // With this, FlatList can calculate everything upfront: const ITEM_HEIGHT = 72; <FlatList getItemLayout={(data, index) => ({ length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index, })} initialScrollIndex={500} // Can jump directly without rendering all above />. Component memoization: const Item = React.memo(({ item, onPress }) => ( <TouchableOpacity onPress={() => onPress(item.id)}> <Text>{item.title}</Text> </TouchableOpacity> ), (prev, next) => prev.item.id === next.item.id && prev.onPress === next.onPress // Custom equality -- only re-render if item changes ); // Stable onPress: const handlePress = useCallback(id => navigate(id), [navigate]);. Window configuration: initialNumToRender={10} // Items rendered before scroll maxToRenderPerBatch={5} // Per batch (scroll) updateCellsBatchingPeriod={50} // ms between batches windowSize={11} // 5 pages above + current + 5 below removeClippedSubviews={true} // Unmount offscreen views. FlashList (recommended for large lists): Shopify's replacement for FlatList — 5-10x faster, no getItemLayout needed: import { FlashList } from "@shopify/flash-list"; <FlashList data={data} renderItem={renderItem} estimatedItemSize={72} />.
10
What are React Native Security Best Practices?
Security in React Native requires awareness of mobile-specific threats: 1. Secure storage: Never use AsyncStorage for sensitive data (tokens, keys, PII) — it's unencrypted and readable. Use: expo-secure-store (Expo) or react-native-keychain (iOS Keychain / Android Keystore — hardware-backed encryption). MMKV with encryption key for semi-sensitive data. 2. Certificate pinning: prevent man-in-the-middle attacks by pinning your server's TLS certificate. Even on compromised networks with fake certificates, the app rejects them: // react-native-ssl-pinning: fetch(url, { sslPinning: { certs: ["my-server-cert-sha256-hash"] } });. 3. Code obfuscation: Hermes compiles to bytecode (harder to read than JS). Additional obfuscation with ProGuard (Android). App binary inspection is still possible — never put secrets in app code. 4. Jailbreak/root detection: import JailMonkey from "jail-monkey"; if (JailMonkey.isJailBroken()) { // Refuse to run or limit functionality }. 5. API secrets: Never hardcode API keys, secrets, or passwords in app code — they're easily extracted from the binary. Use a backend that proxies calls needing secrets. Use environment-specific API keys with limited permissions. 6. Input validation: validate all user input on both client and server. Use parameterized queries to prevent injection. 7. Deep link validation: validate deep link parameters before using — don't blindly navigate based on URL params. 8. Data in transit: always use HTTPS; use certificate pinning for sensitive endpoints; never transmit secrets in URL params (logged by servers, captured by analytics). 9. Local data encryption: encrypt database (SQLCipher for SQLite) and secure-store for all sensitive persisted data. 10. App Transport Security (iOS): enforce ATS in Info.plist — disallows HTTP connections.