Bryn Flow

⚛️ React Native Interview Questions & Answers

The questions that come up again and again in React Native developer interviews, with concise, correct answers — grouped by difficulty.

← React Native Track

Beginner Fundamentals

What is the difference between state and props?

Props are read-only values passed down from a parent component — a child cannot modify them. State is data a component owns and manages internally with useState (or a class's this.state), which changes over time and causes the component to re-render when updated.

What is JSX?

JSX is a syntax extension that lets you write markup-like code directly inside JavaScript to describe UI. It compiles down to plain function calls (React.createElement or the newer JSX transform) — in React Native, that markup maps to native components like View and Text rather than HTML elements.

What does the useEffect hook do?

It runs side effects — code that reaches outside the render (data fetching, subscriptions, timers) — after the component renders. Its dependency array controls when it re-runs: omitted, it runs after every render; empty [], only once on mount; with values, whenever any of those values change. A returned function runs as cleanup before the next run or on unmount.

Why is a key required when rendering a list?

The key gives React (or FlatList) a stable identity for each item across re-renders, so it can efficiently detect which items were added, removed, or reordered instead of re-rendering the whole list from scratch. It should be a stable, unique value like an ID — not the array index, which breaks when items are reordered or removed.

How does styling in React Native differ from CSS on the web?

Styles are JavaScript objects with camelCase property names (defined via StyleSheet.create), not separate CSS files. There's no cascading — a component only receives styles you explicitly pass it — and layout defaults to flexDirection: 'column' rather than the web's row-based block layout.

What is the difference between a controlled and uncontrolled TextInput?

A controlled TextInput has its value driven by React state and updated via onChangeText, so the component's displayed value always matches state — the standard pattern in React Native. An uncontrolled input manages its own internal value and is read via a ref when needed, which is less common but avoids a re-render on every keystroke.

Intermediate Architecture & Performance

Why is FlatList preferred over .map() for rendering long lists?

FlatList virtualizes rendering — it only mounts the rows currently near the visible viewport and recycles them as the user scrolls, keeping memory and render cost roughly constant regardless of list length. Mapping an array directly renders every item up front, which becomes slow and memory-heavy for long lists.

What is the difference between useMemo and useCallback?

useMemo memoizes a computed value, re-running the calculation only when its dependencies change. useCallback memoizes a function reference itself, preventing a new function identity on every render — useful when passing a callback to a memoized child component (React.memo) that would otherwise re-render because it received a "new" function prop each time.

How does navigation state work with React Navigation, and how do you pass data between screens?

React Navigation maintains a stack (or other structure, like tabs) of screens. Data is passed forward via route params: navigation.navigate('Details', { id: 42 }), then read on the target screen with route.params. Passing data back is typically done via a callback param, a shared state/store, or listening for a focus event to refetch when returning to a screen.

What causes unnecessary re-renders in a React Native app, and how do you prevent them?

Common causes: passing new inline object/array/function literals as props every render, state updates higher in the tree re-rendering all children by default, or context value changes re-rendering every consumer. Mitigations: wrap pure components in React.memo, memoize props with useMemo/useCallback, split large contexts into smaller ones, and keep state as local as possible instead of lifting it further than necessary.

What is the difference between AsyncStorage and a SQLite-based solution like WatermelonDB?

AsyncStorage is a simple, asynchronous key-value store — good for small amounts of data like settings or tokens, but not designed for querying, relationships, or large datasets. A SQLite-based library gives you actual relational querying, indexing, and much better performance at scale, at the cost of more setup and a real schema to maintain.

How do you handle platform-specific UI differences?

For small differences, Platform.OS or Platform.select({ ios: ..., android: ... }) branches values inline. For larger, structurally different components, create separate Component.ios.js and Component.android.js files — the Metro bundler automatically picks the correct one for each platform at build time, keeping the shared import path the same.

Advanced Deep Dives

What is the New Architecture (Fabric and TurboModules), and why does it matter?

The legacy architecture communicates between JavaScript and native code over an asynchronous, serialized "bridge," which becomes a bottleneck for high-frequency updates (like gesture-driven animations). Fabric is the new rendering system enabling synchronous, more direct communication for UI updates; TurboModules replaces the old native module system with lazy loading and synchronous JS-to-native calls where needed. Together they reduce bridge overhead and unlock better performance, especially for animation- and gesture-heavy apps.

Why does useNativeDriver matter for the Animated API, and what are its limits?

With useNativeDriver: true, the animation's frame-by-frame updates are sent to the native side once and run entirely on the native UI thread, staying smooth even if the JS thread is busy. Its limitation: it only supports non-layout properties (transform, opacity) — it cannot animate layout properties like width, height, or flex, since those require the JS-driven layout engine to recalculate.

How would you profile and diagnose a janky (dropped-frame) list in a React Native app?

Start with the in-app Perf Monitor or Flipper/React DevTools Profiler to see whether the JS thread or UI thread is the bottleneck. For a janky FlatList, check for: missing/unstable keyExtractor, expensive work inside renderItem (unmemoized components, inline function/style creation causing re-renders), oversized images not pre-resized, and tune windowSize/initialNumToRender/maxToRenderPerBatch to reduce off-screen rendering.

What's the tradeoff between Expo (managed workflow) and a bare React Native project?

Expo's managed workflow gives you a faster setup, over-the-air updates, and a large library of pre-built native modules without touching native code — at the cost of being constrained to what the Expo SDK exposes (though Expo's "config plugins" and prebuild workflow have narrowed this gap significantly). A bare project gives full control over native code, arbitrary third-party native modules, and custom native build configuration, at the cost of managing Xcode/Android Studio projects directly.

How does React's reconciliation work when a list item's key changes versus its content changing?

React diffs children by key: if an item's key stays the same across renders, React reuses the existing component instance and its internal state, updating only the changed props (an efficient in-place update). If the key changes, React treats it as a completely different element — it unmounts the old instance (losing any local state) and mounts a brand-new one, even if the rendered output looks identical. This is why using array index as a key is risky when items can be reordered or removed — it silently reassigns state to the wrong data.

Keep practicing

Take the React Native practice quiz or walk through a full project tutorial.

Practice Quiz