Skip to content
Skip to content
Goodspeed

Getting Started with React Native

Everything you need to know about React Native for mobile app development in 2026.

GUIDE BODY

What Is React Native?

React Native is a framework for building native mobile apps using JavaScript and React. Created by Meta, it lets you write one codebase that runs on both iOS and Android. Unlike hybrid web-based frameworks, React Native produces actual native components, so your app looks and feels like it belongs on each platform.

In 2026, React Native powers apps from Meta, Microsoft, Shopify, Discord, and thousands of indie developers. It is the most practical choice for cross-platform mobile development.

React Native vs. The Alternatives

React Native vs. Flutter

Flutter (by Google) uses Dart and renders its own UI widgets. React Native uses JavaScript/TypeScript and renders actual native components.

  • Choose React Native if: You know JavaScript, want to use the npm ecosystem, or need tight integration with native platform features.
  • Choose Flutter if: You want pixel-perfect custom UI, are comfortable learning Dart, or are building a heavily animated app.

React Native vs. Native (Swift/Kotlin)

Native development gives you the best performance and full access to platform APIs. But you maintain two codebases.

  • Choose Native if: You are building a performance-critical app (games, AR, video editing) or only targeting one platform.
  • Choose React Native if: You want to ship on both platforms with one team, or you are a solo developer.

React Native vs. Web Apps (PWA)

Progressive Web Apps run in the browser. They are easy to deploy but limited in native functionality.

  • Choose PWA if: Your app is content-focused and does not need push notifications, offline storage, or app store distribution.
  • Choose React Native if: You need native features, app store presence, or the performance that comes with native rendering.

Setting Up Your Development Environment

Prerequisites

  • Node.js 18+: Install from nodejs.org
  • A code editor: VS Code is the standard choice
  • Git: For version control
  • Expo CLI: The managed React Native workflow
# Install Expo CLI globally
npm install -g expo-cli

# Create a new project
npx create-expo-app my-app --template expo-template-blank-typescript
cd my-app

# Start the development server
npx expo start

Expo vs. Bare React Native

Expo (Managed Workflow): Handles build configuration, native module management, and OTA updates. You write JavaScript/TypeScript and Expo handles the rest.

Bare React Native: Full control over native code. You manage Xcode and Android Studio projects yourself.

For most apps, Expo is the right choice. You can always eject later if you need custom native code. With Expo Modules and Config Plugins, the need to eject has become rare.

Core Concepts

Components

React Native provides platform-native components:

import { View, Text, TouchableOpacity, FlatList, Image } from 'react-native';

function WelcomeScreen() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text style={{ fontSize: 24, fontWeight: 'bold' }}>
        Welcome to My App
      </Text>
      <TouchableOpacity
        style={{ marginTop: 20, padding: 16, backgroundColor: '#FF4500', borderRadius: 8 }}
        onPress={() => console.log('Pressed!')}
      >
        <Text style={{ color: '#fff', fontWeight: '600' }}>Get Started</Text>
      </TouchableOpacity>
    </View>
  );
}

Key differences from React (web):

  • View instead of div
  • Text instead of span or p (all text must be inside Text components)
  • TouchableOpacity or Pressable instead of button
  • FlatList or SectionList instead of mapped arrays for long lists
  • Image instead of img (requires explicit width and height)

Styling

React Native uses JavaScript objects for styling, not CSS. The layout system is Flexbox, but with some differences:

import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column', // default in RN (row in web CSS)
    padding: 16,
    backgroundColor: '#0D0D0F',
  },
  card: {
    backgroundColor: '#111114',
    borderRadius: 12,
    padding: 16,
    marginBottom: 12,
    borderWidth: 1,
    borderColor: '#1E1E24',
  },
  title: {
    fontSize: 18,
    fontWeight: '600',
    color: '#FFFFFF',
  },
});

Notable differences from CSS:

  • No cascading. Styles do not inherit (except text color within nested Text components).
  • No units. All numbers are density-independent pixels.
  • flexDirection defaults to column, not row.
  • No className. Use the style prop with objects or arrays.

Navigation

Expo Router provides file-based routing, similar to Next.js:

app/
  _layout.tsx          # Root layout (navigation container)
  index.tsx            # Home screen
  (tabs)/
    _layout.tsx        # Tab navigator layout
    home.tsx           # Home tab
    settings.tsx       # Settings tab
  (auth)/
    login.tsx          # Login screen
    signup.tsx         # Signup screen
// app/(tabs)/_layout.tsx
import { Tabs } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';

export default function TabLayout() {
  return (
    <Tabs>
      <Tabs.Screen
        name="home"
        options={{
          title: 'Home',
          tabBarIcon: ({ color }) => (
            <Ionicons name="home" size={24} color={color} />
          ),
        }}
      />
      <Tabs.Screen
        name="settings"
        options={{
          title: 'Settings',
          tabBarIcon: ({ color }) => (
            <Ionicons name="cog" size={24} color={color} />
          ),
        }}
      />
    </Tabs>
  );
}

State Management

For most apps, React's built-in state management is sufficient:

  • useState: Local component state
  • useContext: Shared state across components (auth, theme, settings)
  • useReducer: Complex state logic

For larger apps, consider:

  • Zustand: Simple, lightweight, and TypeScript-friendly
  • TanStack Query (React Query): Server state management with caching, refetching, and pagination
// Simple context for auth state
import { createContext, useContext, useState, useEffect } from 'react';

const AuthContext = createContext<AuthState | null>(null);

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [session, setSession] = useState(null);

  // ... auth logic

  return (
    <AuthContext.Provider value={{ session }}>
      {children}
    </AuthContext.Provider>
  );
}

export const useAuth = () => useContext(AuthContext);

Working with APIs

Fetch Data

React Native includes the fetch API:

async function loadPosts() {
  const response = await fetch('https://api.example.com/posts');
  const data = await response.json();
  return data;
}

Supabase Integration

Supabase provides a typed client that works with React Native:

import { supabase } from '../lib/supabase';

// Read
const { data: posts } = await supabase
  .from('posts')
  .select('*')
  .order('created_at', { ascending: false });

// Write
const { data, error } = await supabase
  .from('posts')
  .insert({ title: 'My Post', body: 'Content here' });

// Real-time subscriptions
supabase
  .channel('posts')
  .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'posts' },
    (payload) => console.log('New post:', payload.new)
  )
  .subscribe();

Performance Tips

FlatList for Long Lists

Never use .map() for lists longer than 20-30 items. FlatList virtualizes the list, only rendering visible items:

<FlatList
  data={items}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <ItemCard item={item} />}
  initialNumToRender={10}
  maxToRenderPerBatch={10}
  windowSize={5}
/>

Avoid Unnecessary Re-renders

  • Use React.memo() for expensive components
  • Use useCallback() for functions passed as props
  • Use useMemo() for expensive calculations

Image Optimization

  • Use expo-image instead of React Native's Image for better caching and performance
  • Resize images on the server (do not send 4K images to display as thumbnails)
  • Use WebP format when possible

Common Pitfalls

SafeAreaView

Modern iPhones have notches and Dynamic Islands. Always wrap your screens with SafeAreaView from react-native-safe-area-context (not from react-native):

import { SafeAreaView } from 'react-native-safe-area-context';
import { SafeAreaProvider } from 'react-native-safe-area-context';

// In _layout.tsx
export default function Layout() {
  return (
    <SafeAreaProvider>
      {/* your app */}
    </SafeAreaProvider>
  );
}

// In screens
export default function HomeScreen() {
  return (
    <SafeAreaView style={{ flex: 1 }}>
      {/* screen content */}
    </SafeAreaView>
  );
}

Platform-Specific Code

Sometimes you need different behavior on iOS vs. Android:

import { Platform } from 'react-native';

const styles = StyleSheet.create({
  shadow: Platform.select({
    ios: {
      shadowColor: '#000',
      shadowOffset: { width: 0, height: 2 },
      shadowOpacity: 0.1,
      shadowRadius: 4,
    },
    android: {
      elevation: 4,
    },
  }),
});

Keyboard Handling

The keyboard covers input fields on mobile. Use KeyboardAvoidingView:

import { KeyboardAvoidingView, Platform } from 'react-native';

<KeyboardAvoidingView
  behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
  style={{ flex: 1 }}
>
  {/* form content */}
</KeyboardAvoidingView>

Building and Deploying

Development Builds

npx expo start           # Start dev server
npx expo start --clear   # Clear cache and start

Preview Builds (for testing)

npx eas build --profile preview --platform ios
npx eas build --profile preview --platform android

Production Builds

npx eas build --profile production --platform all

Over-the-Air Updates

One of Expo's best features. Push JavaScript updates without going through app review:

npx eas update --branch preview --message "Bug fix"

Learning Resources

  • React Native documentation: reactnative.dev
  • Expo documentation: docs.expo.dev
  • React Navigation docs: reactnavigation.org (if not using Expo Router)
  • Supabase React Native guide: supabase.com/docs/guides/getting-started/tutorials/with-expo-react-native

Start with a simple app. A todo list, a notes app, or a habit tracker. Build something small, ship it, and iterate. The best way to learn React Native is to build with it.

Ready to start building?