Learning React Native: A Practical Roadmap
What to learn, in what order, and which traps to avoid when you're starting out building iOS and Android apps with React Native.
React Native lets you build real iOS and Android apps with React and TypeScript. It's not a web page in a wrapper: your components render to genuine native views, so a <View> becomes a UIView on iOS and a ViewGroup on Android.
That makes it one of the most practical ways into mobile development, especially if you already know React. But mobile has its own rules, and a lot of the frustration beginners feel comes from treating a phone like a small browser.
This post is the roadmap I'd follow if I were starting today: what to learn, in what order, and what to watch out for.
Step 0: Get Comfortable with React and TypeScript
React Native is React. Before touching mobile, make sure you're comfortable with:
- Function components, props, and JSX
useState,useEffect,useMemo, anduseCallback- Lifting state up and passing callbacks down
- TypeScript basics: types for props, state, and API responses
If you've built a small React web app, you're ready. If you haven't, spend a week on that first. It will make everything else much easier.
Step 1: Start with Expo
The React Native docs recommend starting with a framework, and Expo is the standard choice. It handles the painful parts of native tooling for you: build configuration, native modules for the camera, location, notifications and more, plus over-the-air updates and cloud builds.
npx create-expo-app@latest my-first-app
cd my-first-app
npx expo start
Scan the QR code with the Expo Go app on your phone and your app is running on a real device in under a minute. Edit a file, save, and it updates instantly.
A common worry is that Expo will limit you later. These days that's rarely true. With development builds you can add any native library and still keep Expo's tooling. You don't need to "eject."
Step 2: Unlearn the DOM
This is where web developers stumble most. There's no HTML and no CSS files. Instead you get a small set of core components:
| Web | React Native |
|---|---|
<div> | <View> |
<p>, <span> | <Text> (all text must be inside <Text>) |
<img> | <Image> |
<button> | <Pressable> |
<input> | <TextInput> |
Scrolling <div> | <ScrollView> or <FlatList> |
Styling uses JavaScript objects, with a subset of CSS and Flexbox for layout:
import { useState } from "react";
import { Pressable, StyleSheet, Text, View } from "react-native";
export function Counter() {
const [count, setCount] = useState(0);
return (
<View style={styles.container}>
<Text style={styles.count}>{count}</Text>
<Pressable
onPress={() => setCount((c) => c + 1)}
style={({ pressed }) => [styles.button, pressed && styles.pressed]}
>
<Text style={styles.buttonText}>Tap me</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, alignItems: "center", justifyContent: "center", gap: 16 },
count: { fontSize: 48, fontWeight: "700" },
button: { backgroundColor: "#4f46e5", paddingHorizontal: 24, paddingVertical: 12, borderRadius: 999 },
pressed: { opacity: 0.7 },
buttonText: { color: "white", fontSize: 16, fontWeight: "600" },
});
A few things that catch people out:
- Flexbox defaults to
column, notrowlike on the web. - Units are density-independent pixels. You write
16, not"16px"or"1rem". - Styles don't cascade. A
<View>'s font settings don't apply to the<Text>inside it. Nested<Text>is the one exception. - Strings outside
<Text>crash the app. A stray space or{count}sitting directly inside a<View>will throw an error.
Step 3: Navigation
Mobile navigation works differently from web routing. Screens are stacked on top of each other, with tabs, modals, and gestures like swipe-to-go-back.
If you're using Expo, start with Expo Router, which uses file-based routing like Next.js:
app/
├── _layout.tsx # root stack
├── (tabs)/
│ ├── _layout.tsx # bottom tab bar
│ ├── index.tsx # Home tab
│ └── profile.tsx # Profile tab
└── product/[id].tsx # pushed on top of the tabs
import { Link } from "expo-router";
<Link href={`/product/${product.id}`}>View details</Link>
Under the hood it's built on React Navigation, the long-standing community standard, so what you learn carries over either way. Spend time understanding the difference between stack, tab, and modal navigation. Getting this structure right early saves a lot of rewriting later.
Step 4: Lists, Data, and Performance
Almost every app is mostly lists. Learn FlatList early, and never render a long list with .map() inside a ScrollView:
<FlatList
data={products}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <ProductRow product={item} />}
ItemSeparatorComponent={Divider}
onEndReached={loadMore}
refreshing={isRefreshing}
onRefresh={refresh}
/>
FlatList only renders what's on screen (plus a small buffer), which keeps memory and frame rate under control. For very long or complex lists, look at FlashList from Shopify.
For fetching data, a library like TanStack Query handles caching, retries, background refetching, and loading states. That's especially valuable on mobile, where networks are slow, flaky, or missing entirely.
Performance habits worth building from day one:
- Keep list items light, and use
React.memofor rows that re-render often. - Avoid heavy work in render. Move it into
useMemoor off the main thread. - Use Reanimated for animations so they run on the UI thread and stay smooth.
- Test on a real, mid-range Android device. The simulator on a fast laptop hides problems your users will feel.
Step 5: Think Like a Mobile Developer
This is the step most tutorials skip, and it's what separates an app that works from one that feels native:
-
Safe areas. Notches, rounded corners, and home indicators. Use
react-native-safe-area-contextso content isn't hidden under them. -
The keyboard. It covers your inputs. Learn
KeyboardAvoidingViewor a keyboard-aware scroll library. -
Platform differences. iOS and Android users expect different things. Use
Platform.OSorPlatform.selectwhen it matters:const shadow = Platform.select({ ios: { shadowColor: "#000", shadowOpacity: 0.1, shadowRadius: 8, shadowOffset: { width: 0, height: 4 } }, android: { elevation: 4 }, }); -
App lifecycle. Apps get backgrounded, suspended, and killed. Use
AppStateto refresh data when the user returns. -
Offline and slow networks. Show cached data, handle failures gracefully, and never leave a spinner running forever.
-
Permissions. Ask for camera, location, or notifications at the moment they're needed, with a clear reason, not all at once on launch.
-
Secure storage. Tokens belong in the iOS Keychain or Android Keystore (for example via
expo-secure-store), not inAsyncStorage. -
Accessibility. Add
accessibilityLabelandaccessibilityRole, support dynamic font sizes, and try your app with VoiceOver and TalkBack.
Step 6: Understand What's Under the Hood
You don't need to write native code to be productive, but understanding the architecture helps you debug and make good decisions.
React Native's New Architecture is now the default. In short:
- Your JavaScript runs on Hermes, a JavaScript engine built for React Native that starts fast and uses little memory.
- JSI lets JavaScript call native code directly, replacing the old asynchronous "bridge" that serialised every message to JSON.
- Fabric is the new rendering system, and TurboModules load native modules lazily, only when they're first used.
Practically, this means smoother UI and faster startup, and it's worth checking that the libraries you choose support the New Architecture.
Eventually you'll want to read a bit of Swift and Kotlin too. Not to rewrite your app, but to understand a native library's source, read a crash log, or write a small native module when you need a platform feature no library covers.
Step 7: Ship It
Building an app and releasing an app are two different skills. Learn the release process early, not the week before launch:
- EAS Build creates signed iOS and Android builds in the cloud, so you don't need to fight local certificates on day one.
- TestFlight (iOS) and internal testing tracks (Google Play) get your app onto testers' phones.
- Over-the-air updates (EAS Update) let you ship JavaScript fixes without a store review. Use them for fixes, not to sneak in major features.
- Crash reporting with a tool like Sentry tells you what's breaking for real users.
- Store listings need screenshots, privacy details, and a description. Allow time for App Store review, especially for your first submission.
A Realistic Learning Plan
| Week | Focus | Build this |
|---|---|---|
| 1 | Core components, styling, Flexbox | A static profile screen and a counter |
| 2 | Navigation | A tab app with a list screen and a details screen |
| 3 | Data and lists | Fetch from a public API with FlatList, pull-to-refresh, and loading/error states |
| 4 | Native features | Add the camera or location, with proper permission handling |
| 5 | Polish | Safe areas, keyboard handling, dark mode, accessibility |
| 6 | Ship | Build with EAS and get it onto TestFlight or a Play internal track |
Like any skill, the key is one project that grows rather than a dozen half-finished tutorials. By week six you'll have a real app on a real phone, and you'll understand every part of it.
Common Beginner Mistakes
- Rendering long lists with
ScrollViewand.map()instead ofFlatList. - Only testing on the iOS simulator, then discovering Android looks different.
- Ignoring the keyboard, safe areas, and small screens until the end.
- Installing a library for everything. Each native dependency is something you'll need to keep updated.
- Storing auth tokens in
AsyncStorageinstead of secure storage. - Treating the app like a website: expecting hover states, mouse input, and constant connectivity.
Wrapping Up
React Native is a great way to build mobile apps, especially if you already know React. The JavaScript is the easy part. The real learning is in thinking like a mobile developer: designing for touch, small screens, unreliable networks, and two platforms with their own conventions.
Start with Expo, build one app that grows week by week, test on real devices, and ship something to a real store. That's when it all clicks.
Thanks for reading! If you're learning React Native, I'd love to hear what you're building.
Written by
Niluka Bandara
Lead Mobile Developer in Stockholm, building Flutter apps for fintech and payments.