React Native Tutorial: Learn Mobile from Scratch (2026)
I came to React Native after years of building web apps with React. The mental model was familiar — components, props, state — but the mobile context changed everything. No more divs and spans; now I had View, Text, and ScrollView. No more CSS cascade; now I used StyleSheet.create with Flexbox. The first time I saw my JavaScript code render a native button on an iPhone, I was hooked. This tutorial distills the practical knowledge I gained shipping three React Native apps to both stores, including the painful lessons about bridging native modules and profiling performance.
Setting Up Your React Native Environment
React Native gives you two paths: Expo and bare React Native CLI. Expo handles the build toolchain, Xcode, and Android Studio configuration for you — ideal for beginners. The CLI approach gives you full control over native modules but requires managing Gradle, CocoaPods, and provisioning profiles yourself. I recommend starting with Expo because you can run npx create-expo-app and have a working app on your phone via Expo Go in under five minutes. For either path, you need Node.js 18+, Watchman on macOS, and either Xcode (iOS) or Android Studio (Android). Run npx react-native doctor to check your environment.
npx create-expo-app MyFirstApp
cd MyFirstApp
npx expo start
Core Components and JSX
React Native replaces HTML tags with a set of core components. View is the universal container like a div. Text must wrap every string you render. ScrollView provides scrolling, and FlatList renders long lists efficiently with virtualization. TextInput replaces input fields, and Pressable handles touch interactions. The styling uses a subset of CSS via JavaScript objects — no classes or inheritance. Flexbox is the default layout model, and the flex direction defaults to column instead of row. This took me a while to internalize, but once you learn the mapping, building UIs becomes intuitive.
Hello, React Native
Tap Me
State, Props, and Component Lifecycle
React Native uses the same React patterns you know from the web. Functional components with hooks are the standard. useState manages local component state, useEffect handles side effects like subscriptions or timers, and useCallback prevents unnecessary re-renders by memoizing functions. Props flow downward from parent to child. The tricky part is understanding that React Native's render cycle runs on a JavaScript thread separate from the UI thread. Expensive computations can cause dropped frames. Use InteractionManager.runAfterInteractions to defer heavy work until animations complete.
const [count, setCount] = useState(0);
useEffect(() => { console.log('Mounted'); }, []);
const increment = useCallback(() => setCount(c => c + 1), []);
Navigation with React Navigation
Navigation in React Native is not built-in. The community standard is React Navigation, a JavaScript-based navigator that supports stacks, tabs, drawers, and modals. You wrap your app in a NavigationContainer and define navigators inside. A stack navigator pushes and pops screens like a browser history. A tab navigator gives you bottom tabs with icons. The trick I learned is to use useFocusEffect instead of useEffect for screens that need to refresh data every time they come into view — useEffect only fires once per mount, but tabs can stay mounted across switches.
const Stack = createNativeStackNavigator();
Working with Native Modules and Device APIs
React Native provides core modules for common device features — Camera, Location, Notifications, AsyncStorage. For anything not covered, you write a native module or use a community library. The Expo SDK bundles most of these as installable packages. When you need to bridge custom native code, you write an Objective-C class (iOS) or a Java/Kotlin class (Android) that extends ReactContextBaseJavaModule or implements RCTBridgeModule, annotate methods with @ReactMethod, and register it. The bridge serializes arguments as JSON, so keep payloads small.
@ReactMethod
public void showToast(String message) {
Toast.makeText(getReactApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
Performance Optimization and App Store Release
Performance in React Native requires vigilance. Use FlatList instead of ScrollView for large datasets — it virtualizes rows and recycles views. Memoize components with React.memo and expensive calculations with useMemo. The Hermes engine, now the default, improves startup time and reduces memory by precompiling JavaScript to bytecode. For release, configure code signing in Xcode and Android Studio, increment version numbers in app.json, and run eas build (Expo) or npx react-native build (CLI) to produce the final binaries.
eas build --platform ios --profile production
eas submit --platform ios --latest
Frequently Asked Questions
Should I use Expo or bare React Native CLI?
Start with Expo. It simplifies the build process and lets you test immediately. If you need a native module that Expo does not support, you can eject to a bare workflow or use expo-dev-client to keep the managed experience.
Can I reuse web React components in React Native?
Not directly. DOM APIs and many HTML components do not exist in React Native. However, you can share business logic, hooks, state management, and API utilities. Libraries like react-native-web or Tamagui help bridge the gap for web reuse.
Why is my FlatList scrolling slowly?
Ensure you are providing a unique key prop, using getItemLayout for fixed-size rows, and avoiding inline functions in renderItem. Also check that images are properly sized and cached with FastImage.
How do I debug React Native apps?
Expo Go includes a developer menu with inspector and network logging. For bare projects, use Flipper (Facebook's debugger) or the Chrome DevTools via the debugger proxy. React DevTools also work for inspecting component trees.
Originally published on Ayodhyyya. Last updated June 1, 2026.