React Native interview questions

Reviewed by Mark Dickie · Last updated

4 questions on this page you can answer and see marked on the spot. Go to the first one

React Native is a JavaScript framework that lets you build native iOS and Android apps from a single codebase using React's component model. For interviews, you need to know how the bridge architecture moves data between JS and native threads, how styling and Flexbox differ from web CSS, and how to spot common performance pitfalls like unnecessary re-renders and heavy work on the JS thread.

Most questions cluster around four areas: the component lifecycle and hooks, navigation patterns, platform-specific code with Platform.OS, and performance tuning. You should also be comfortable explaining how FlatList virtualizes rows, why ScrollView can choke on large data, and what the new architecture (Fabric renderer, TurboModules) changes about threading.

What does a React Native interview typically cover?

AreaWhat they askKey concepts
Components & hooksLifecycle, state, side effectsuseEffect deps, useCallback, re-render triggers
NavigationStack vs tab vs drawerReact Navigation, deep linking, params
PerformanceList rendering, thread loadFlatList virtualization, InteractionManager
Native bridgeJS↔native communicationNativeModules, requireNativeComponent, TurboModules
Platform codeiOS/Android differencesPlatform.OS, Platform.select, conditional imports
  1. Explain the React Native bridge and why heavy computation on the JS thread drops frame rate.
  2. Compare FlatList and ScrollView: when does each make sense, and what does virtualization actually do?
  3. Walk through how useEffect works in a React Native component and what changes when a dependency is stale.
  4. Describe how you'd share most of a codebase between iOS and Android while still calling platform-specific APIs.
  5. Outline what the Fabric renderer and TurboModules change about how your app boots and renders.

How should you prepare for a React Native interview?

Start by building a small app that exercises navigation, a scrollable list, and a native module call. That gives you concrete stories for behavioral follow-ups. Pair that with focused review of the bridge model and the hooks rules of thumb, since those are the most common failure points for candidates who have only used Expo and never touched native code.

Key facts

  • Tarmac has 116 React Native interview questions on this topic, 10 of them on this page, at difficulty 1–5 of 5.
  • Tarmac tracked 216 job postings asking for React Native in October 2026.
  • Roles asking for React Native advertise a median base salary of US$169,525, across 90 job postings as of October 2026.
  • Tarmac last reviewed these React Native interview questions on 19 October 2026.

At a glance

Questions10 shown · 116 in the bank
Difficulty1–5 of 5
FormatsTrue / false, Fill in the blank, Short answer, Ordering, Multiple choice, Code output, Flashcard, Multiple answer, Coding exercise, Find the bug
Interactive1 run your code against tests, in the app

What you'll review

  1. core components
  2. debugging tooling
  3. lists performance
  4. hooks lifecycle

Practice questions

Try one before you open the answer. Pick an option and press Check; it's marked on the spot.

True or False: In React Native, a ScrollView renders all of its child components at mount time, while a FlatList uses virtualization to render only the items currently visible (or near the viewport), which generally makes FlatList more memory-efficient for long lists.#

Options

Show answer

True. A ScrollView mounts and renders all children up front, which is acceptable for short, bounded content but costly for large lists. A FlatList virtualizes its rows, rendering only items near the visible viewport and recycling off-screen components, so its memory footprint stays roughly constant as data grows.

Why:

ScrollView lays out and renders every child immediately — fine for small, fixed collections but memory-heavy for hundreds of rows. FlatList is built on VirtualizedList under the hood: it mounts only the window of items near the viewport and recycles off-screen rows, so memory usage stays roughly constant as the data set grows.

The fundamental building block for UI layout in React Native is the _____ component. It maps to the native platform equivalent — UIView on iOS and android.view.View on Android — and supports Flexbox-based styling via the style prop.#

Show answer

The fundamental building block for UI layout in React Native is the View component. It maps to the native platform equivalent — UIView on iOS and android.view.View on Android — and supports Flexbox-based styling via the style prop.

Why:

View is the core container primitive in React Native. Every layout — whether wrapping text, images, or other components — is composed of View nodes that map directly to native views, and React Native applies Flexbox rules (via Yoga) to position them.

Starting with React Native 0.73, what is the name of the official built-in debugging toolset that replaces the legacy Flipper-based integration for inspecting layout, network, and logs?#

Show answer

React Native DevTools

Why:

React Native 0.73 introduced React Native DevTools, a first-party, built-in debugger that replaces the older Flipper-based workflow. It integrates directly with Metro and provides layout inspection, network inspection, console logs, and JavaScript debugging without requiring an external app.

Order these React Native list components from worst to best scrolling performance for a flat list with 1,000 items.#

Put these in order

Show answer

For a 1,000-item list, ScrollView is the worst performer because it mounts every item up front. FlatList is better because it virtualizes, mounting only visible items plus a buffer. FlashList is the best because it adds component recycling on top of virtualization, reusing component instances during scroll for even smoother performance.

Why:

ScrollView renders all 1,000 items at once, causing heavy memory and CPU usage on mount and scroll. FlatList virtualizes by mounting only the items in the visible window plus a configurable buffer, dramatically reducing work. FlashList (by Shopify) adds component recycling on top of virtualization, reusing mounted component instances rather than creating and destroying them, which yields even smoother scrolling for large lists.

You need to render a potentially very long list of user records in a React Native app. Which built-in core component is designed to keep memory low by recycling off-screen rows and only mounting items near the current viewport?#

Options

Show answer

Use FlatList for long lists in React Native. It virtualizes its rows through an underlying VirtualizedList, recycling off-screen items so only those near the viewport stay mounted — keeping memory usage low. ScrollView renders all children at once and is unsuitable for large datasets, while VirtualizedList is the low-level primitive FlatList wraps and is not meant for direct app-screen use.

Why:

FlatList is the React Native core component purpose-built for long lists: it virtualizes its children via an underlying VirtualizedList, recycling rows that scroll off-screen so only items near the viewport are mounted. ScrollView, by contrast, renders every child at once, which causes memory and performance issues for large lists. SectionList builds on the same virtualization machinery but adds section headers — view recycling is not exclusive to it. VirtualizedList is the lower-level primitive FlatList wraps; it is not intended for direct use in typical app screens.

Consider the following React Native functional component. No external state changes occur — only what is shown in the code determines the output. What appears in the console, in order, after the component mounts and all resulting effect cycles settle?#

import React, { useState, useEffect } from 'react';

function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setCount(count + 1);
  }, []);

  useEffect(() => {
    console.log(count);
  }, [count]);

  return null;
}

export default App;
Show answer
0
1
Why:

On the initial mount, both effects run in declaration order. The first effect (empty dependency array) calls setCount(0 + 1), scheduling a re-render, but the state update is not applied yet during this effect cycle. The second effect runs immediately after with count still equal to 0, printing 0. React then re-renders with count = 1. The first effect does not re-run (its deps array is empty and unchanged). The second effect's dependency [count] changed from [0] to [1], so it runs again and prints 1. No further state updates occur, so the output is 0 then 1.

In React Native function components, the effect from useEffect does not run synchronously during render. What two internal phases does React separate the work into, and when does useEffect actually fire relative to them?#

Show answer

The render phase is where React calls your function component, diffs the returned tree, and determines what to change. It must be pure and side-effect-free. The commit phase is where React applies those changes to the host (e.g., updates native views via the UIManager) — this is when useEffect cleanup and setup callbacks fire, after the UI has been flushed to the screen.

Why:

React's reconciler splits work into a pure render phase (compute the diff) and a side-effect commit phase (apply to the host tree). useEffect callbacks are scheduled after the commit phase completes, so the screen has already been updated before they run — this is why reading or mutating native views inside useEffect is safe, but doing so during render is not.

A FlatList in a React Native 0.74 app renders 5,000 rows, each backed by a complex custom component. Scrolling is janky and the app's memory footprint is high. Which of the following changes will measurably help address these problems?#

Options

Pick every one that applies.

Show answer

The helpful changes are: wrapping the row in React.memo (skips re-renders of unchanged rows), reducing windowSize (fewer offscreen items mounted, less memory and render work), providing getItemLayout (O(1) position calculation, no runtime layout measurement), and supplying a stable unique keyExtractor (prevents unnecessary unmount/remount on data changes). Setting initialNumToRender to the full data length is harmful — it defeats virtualization, rendering every row synchronously on first paint.

Why:

Each correct option targets a distinct layer of the virtualization pipeline. React.memo on the row prevents React from re-rendering every visible row when the parent re-renders — without it, a parent state change re-renders all 5,000 row instances that are currently mounted. Lowering windowSize reduces the number of offscreen items FlatList keeps mounted on either side of the viewport, directly cutting memory usage and the render work that happens during scroll. getItemLayout lets VirtualizedList compute an item's pixel offset and length arithmetically, eliminating the native layout-measurement pass for every item and enabling O(1) scrollToIndex. A stable, unique keyExtractor lets React's reconciler match existing row instances across data changes; without it, items may unmount and remount unnecessarily, thrashing memory and causing jank. Setting initialNumToRender to the full data length is the opposite of an optimization: it defeats virtualization by rendering all 5,000 rows synchronously on first paint, spiking memory and blocking the main thread.

In React Native, SectionList internally flattens its sections prop into a single flat array and computes which indices are sticky headers so the underlying VirtualizedList can pin them during scroll. Replicate that flattening logic yourself.#

Starter code

function flattenSections(sections) {
  const data = [];
  const stickyHeaderIndices = [];
  // TODO: iterate over sections, push header + row items into `data`,
  // and record the index of each header in `stickyHeaderIndices`.
  return { data, stickyHeaderIndices };
}

Your solution must pass

  • two_sections

This one is written and run, not read. Solve it in the app and your code is executed against these tests and the hidden ones.

A React Native (0.74, Hermes) screen renders a 5 000-row FlatList. Featured rows (every 50th item) are twice as tall as normal rows. The developer enables every common virtualization optimization but scrollToIndex({ index: 100 }) consistently overshoots the target and some featured rows flicker when scrolled into view. Identify the buggy line(s) in the configuration below.#

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

const data = Array.from({ length: 5000 }, (_, i) => ({
  id: String(i),
  label: `Row ${i}`,
  featured: i % 50 === 0,
}));

const MyList = () => (
  <FlatList
    data={data}
    keyExtractor={(item) => item.id}
    renderItem={({ item }) => (
      <View style={[styles.row, item.featured && styles.featuredRow]}>
        <Text>{item.label}</Text>
      </View>
    )}
    getItemLayout={(_, index) => ({
      length: 60,
      offset: 60 * index,
      index,
    })}
    initialNumToRender={8}
    maxToRenderPerBatch={8}
    windowSize={10}
    removeClippedSubviews={true}
  />
);

const styles = StyleSheet.create({
  row: { height: 60, padding: 12 },
  featuredRow: { height: 120, backgroundColor: '#fef3c7' },
});
Show answer

The bug is on lines 20 and 21.

Why:

getItemLayout is an opt-in contract that tells VirtualizedList the exact pixel position and height of every item so it can skip on-mount measurement and jump to any index in O(1). Here, styles.featuredRow (height: 120) overrides styles.row (height: 60) for every 50th item because React Native merges style arrays left-to-right, so featured rows are actually 120 px tall. Yet lines 20–21 hard-code a uniform length of 60 and compute offset as 60 * index, ignoring the extra 60 px contributed by each featured row. The cumulative offset drifts by 60 px for every featured row before the target, so scrollToIndex overshoots; the virtualization window also miscalculates which cells intersect the viewport, causing featured rows to pop in late. The fix is either to compute the real cumulative offset (summing actual heights) inside getItemLayout, or to remove getItemLayout entirely so VirtualizedList falls back to measuring each cell. removeClippedSubviews, windowSize, initialNumToRender, and maxToRenderPerBatch are all correctly configured and do not cause this symptom.

Related interview questions

Job market

See react-native salaries and hiring demand from live job postings.

The other 106 questions

This page shows 10 and marks what you pick. That's as far as a page can go. A free account opens the other 106 and keeps every answer. What you miss comes back until it's right: after a day, then at longer gaps.

Start with this topic

Free · the whole bank · 100 marked answers per 30 days · written feedback on the paid plan

Interview booked? Practise the job ad instead

What moved, monthly

One email a month when the bulletin comes out: what moved in the markets we track, and the new question topics we published. Confirm your address to join. Unsubscribe any time.