Skip to content

Introduction to React Native

React Native, introduced by Facebook (now Meta) in 2015, revolutionized mobile development by allowing developers to build native-performing iOS and Android apps from a single JavaScript codebase. It renders using actual native UI components, creating apps indistinguishable from those built with Swift or Kotlin.

Key Benefits:

  • Reduced development time and cost.
  • Significant code sharing between platforms.
  • Faster iteration with Hot Reloading.
  • Access to native device features.
  • Easier transition for web developers into mobile development.

The New Architecture

React Native’s New Architecture significantly improves performance and capabilities by replacing the old asynchronous bridge. It consists of several key components:

JavaScript Interface (JSI)

A C++ layer enabling direct, synchronous communication between JavaScript and native code, eliminating the need for JSON serialization used by the old bridge. Benefits: Faster performance, lower memory usage, quicker startup, enables modern React features like Suspense.

Turbo Modules

The evolution of Native Modules. They load lazily (only when needed) and use JSI for direct, efficient communication with native platform APIs. Benefits: Lazy loading, direct JSI communication (faster), supports sync/async calls, type-safe (via CodeGen), better memory management.

Fabric

The new rendering system. It uses JSI for direct UI manipulation and enables multi-threaded rendering for a smoother user experience. Benefits: Multi-threaded rendering, synchronous layout potential, direct native UI access via JSI, improved state management with persistent C++ UI trees.

Old Bridge vs. New Architecture (JSI)

  • Asynchronous communication only.
  • Used JSON serialization/deserialization (overhead).
  • All Native Modules loaded at startup.
  • Single-threaded UI updates.
  • Slower performance and higher memory usage.

Expo: Simplifying React Native Development

Expo is an open-source framework and platform built on top of React Native. It provides a managed workflow with pre-built tools and services, abstracting away much of the native configuration complexity.

Core Features:

  • Expo CLI: Development command-line tool.
  • Expo Go: A client app to instantly run projects on physical devices without native builds.
  • Expo SDK: A curated set of native APIs and components (location, camera, etc.).
  • EAS (Expo Application Services): Cloud build, submission, and update services.

Why Recommended:

  • Rapid Start: Minimal setup required (npx create-expo-app).
  • Simplified Workflow: Often avoids direct interaction with native Xcode/Android Studio projects.
  • Easy Testing: Instantly preview on devices using Expo Go.
  • Over-the-Air (OTA) Updates: Push JS updates directly to users via EAS Update.
  • Managed Builds: EAS Build handles native compilation in the cloud.

Expo Go vs. Development Builds

Expo offers two main ways to run your app during development:

What: A pre-built app from the App/Play Store containing the Expo SDK. Pros:

  • Fastest way to start and test.
  • No native build tools needed initially.
  • Instantly run code on a physical device. Cons:
  • Limited to native modules included in the Expo SDK version.
  • Cannot add custom native code or libraries not in Expo Go.
  • Limited native configuration (app icon, splash screen require a build). Use When: Starting new projects, prototyping, learning, apps using only Expo SDK APIs.

React vs. React Native Syntax

While built on React, React Native uses native components instead of web elements (HTML DOM).

Similarities:

  • JSX syntax.
  • Component-based architecture.
  • React Hooks (useState, useEffect, etc.).
  • Props system.
  • State management principles.

Key Differences:

// React (Web)
<div>
<h1>Title</h1>
<p>Paragraph</p>
<img src="..." alt="..." />
<input type="text" />
</div>
// React Native
import { View, Text, Image, TextInput } from 'react-native';
<View>
<Text style={{fontWeight: 'bold'}}>Title</Text>
<Text>Paragraph</Text>
<Image source={{ uri: '...' }} style={{width: 50, height: 50}} />
<TextInput />
</View>

Environment Setup

Choose the setup method that best suits your needs.

The quickest way to get started.

  1. Install Expo CLI (Optional but Recommended):
    Terminal window
    npm install -g expo-cli
  2. Create a New Project:
    Terminal window
    npx create-expo-app@latest YourProjectName
    cd YourProjectName
  3. Start the Development Server:
    Terminal window
    npx expo start
    Scan the QR code with the Expo Go app on your device, or use the commands to open in an emulator/simulator. For custom native code, create a Development Build (see above).

2. Using React Native CLI (Bare Workflow)

Provides full control over the native project files. Requires more setup.

General Steps (Summarized - Refer to Official Docs for Details):

  1. Install Core Dependencies:
    • Node.js: Use the LTS version.
    • Watchman: (Recommended for macOS/Linux) File watching service. brew install watchman
    • Java Development Kit (JDK): Typically OpenJDK 17. Use package managers like brew (macOS) or download directly. Set JAVA_HOME.
  2. Install Android Dependencies:
    • Android Studio: Install the latest version.
    • Android SDK: Use Android Studio’s SDK Manager to install the required SDK Platform (e.g., Android 14 - API 34) and Build-Tools. Ensure Command-line Tools are installed.
    • Emulator/Device: Set up an Android Virtual Device (AVD) via Android Studio or enable USB Debugging on a physical device.
    • Configure Environment Variables: Set ANDROID_HOME and add platform-tools/emulator to your PATH.
  3. Install iOS Dependencies (macOS Only):
    • Xcode: Install from the Mac App Store.
    • Xcode Command Line Tools: Install via Xcode or xcode-select --install.
    • CocoaPods: Dependency manager for iOS. sudo gem install cocoapods
  4. Create React Native CLI Project:
    Terminal window
    npx react-native@latest init YourProjectName
    cd YourProjectName
  5. Run the App:
    • Start Metro Bundler: npx react-native start (or npm start / yarn start).
    • (New Terminal) Run on Platform:
      Terminal window
      # Android
      npx react-native run-android
      # iOS (macOS only)
      npx react-native run-ios
      iOS may require cd ios && pod install && cd .. first.

Device Connection Tips:

  • Android USB: Enable Developer Options & USB Debugging. Connect via USB. Verify with adb devices.
  • Android WiFi: Enable Wireless Debugging. Pair device (adb pair ...). Connect (adb connect ...).
  • iOS USB (macOS): Connect via USB. Trust the computer. May need Apple Developer account setup in Xcode.
  • Reverse Tethering (for accessing local dev server): adb reverse tcp:8081 tcp:8081 (Ensure Metro runs on port 8081).

Styling with TailwindCSS (NativeWind)

NativeWind brings the utility-first power of TailwindCSS to React Native. It compiles Tailwind classes into StyleSheet objects.

Integrating NativeWind v4+ (CLI Project)

This setup uses Metro to process a global CSS file.

  1. Install Dependencies:

    Terminal window
    npm install nativewind tailwindcss react-native-reanimated react-native-safe-area-context
    # or yarn add ..., pnpm add ..., bun add ...
  2. Link Native Dependencies (iOS):

    Terminal window
    npx pod-install
  3. Initialize & Configure Tailwind:

    • Generate config: npx tailwindcss init
    • Edit tailwind.config.js:
      tailwind.config.js
      /** @type {import('tailwindcss').Config} */
      module.exports = {
      content: [
      "./App.{js,jsx,ts,tsx}",
      "./src/**/*.{js,jsx,ts,tsx}" // Adjust paths as needed
      ],
      presets: [require("nativewind/preset")], // Add preset
      theme: { extend: {} },
      plugins: [],
      }
    • Create global.css (e.g., in root or ./src):
      global.css
      @tailwind base;
      @tailwind components;
      @tailwind utilities;
  4. Configure Babel: Add the preset to babel.config.js.

    babel.config.js
    module.exports = {
    presets: [
    'module:@react-native/babel-preset',
    'nativewind/babel' // Add NativeWind preset
    ],
    plugins: [
    // Reanimated plugin must be LAST
    'react-native-reanimated/plugin',
    ],
    };
  5. Configure Metro: Use withNativeWind in metro.config.js.

    metro.config.js
    const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config");
    const { withNativeWind } = require("nativewind/metro");
    /** @type {import('metro-config').MetroConfig} */
    const config = {}; // Your base config
    module.exports = withNativeWind(
    mergeConfig(getDefaultConfig(__dirname), config),
    {
    // Correct relative path to your CSS file:
    input: "./global.css",
    // Optional output file name:
    // output: "nativewind-output.js",
    }
    );
  6. Import CSS in App Entry: Import the CSS file in App.js or App.tsx.

    App.tsx
    import "./global.css"; // Import the CSS file
    import React from 'react';
    // ... other imports
    import { SafeAreaView, View, Text } from 'react-native';
    const App = () => {
    return (
    <SafeAreaView className="flex-1 items-center justify-center">
    <Text className="text-xl text-blue-600 dark:text-blue-400">
    Hello NativeWind!
    </Text>
    </SafeAreaView>
    );
    };
    export default App;
  7. TypeScript Setup (If using TS): Create a type definition file (e.g., nativewind-env.d.ts).

    /// <reference types="nativewind/types" />
  8. Restart with Cache Reset: Crucial after config changes!

    Terminal window
    npm start -- --reset-cache
    # or yarn start --reset-cache

    Then run npx react-native run-android or run-ios in another terminal.