Module 1 • 50 min read

React Native: Build iOS & Android Apps

Learn to build native mobile apps using React and JavaScript for both platforms.

What You'll Learn

  • Setting up React Native development environment
  • Core components and navigation
  • Styling and responsive layouts
  • Working with APIs and async storage

1. Getting Started

React Native lets you build mobile apps using React. Write once, run on both iOS and Android. It uses native components instead of web components, giving you true native performance.

Setup Your Project

# Install Expo CLI (easiest way to start)
npm install -g expo-cli

# Create new project
npx create-expo-app MyApp
cd MyApp

# Start development server
npx expo start

# Or use React Native CLI for more control
npx react-native init MyApp
cd MyApp
npx react-native run-ios    # For iOS
npx react-native run-android # For Android

2. Core Components

React Native provides built-in components that map to native UI elements. Unlike web development, you use View instead of div, Text instead of p, etc.

Basic Components

import React from 'react';
import {
  View,
  Text,
  Image,
  ScrollView,
  TextInput,
  Button,
  TouchableOpacity,
  StyleSheet
} from 'react-native';

export default function App() {
  const [text, setText] = React.useState('');

  return (
    <ScrollView style={styles.container}>
      {/* View is like a div */}
      <View style={styles.header}>
        <Text style={styles.title}>Welcome to React Native</Text>
      </View>

      {/* Image component */}
      <Image
        source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
        style={styles.logo}
      />

      {/* Text Input */}
      <TextInput
        style={styles.input}
        placeholder="Enter your name"
        value={text}
        onChangeText={setText}
      />

      {/* Button */}
      <Button
        title="Press Me"
        onPress={() => alert(`Hello ${text}!`)}
      />

      {/* Touchable for custom buttons */}
      <TouchableOpacity 
        style={styles.customButton}
        onPress={() => console.log('Pressed')}
      >
        <Text style={styles.buttonText}>Custom Button</Text>
      </TouchableOpacity>
    </ScrollView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  header: {
    padding: 20,
    backgroundColor: '#007AFF',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#fff',
  },
  logo: {
    width: 100,
    height: 100,
    alignSelf: 'center',
    margin: 20,
  },
  input: {
    height: 40,
    margin: 12,
    borderWidth: 1,
    padding: 10,
    borderRadius: 5,
  },
  customButton: {
    backgroundColor: '#007AFF',
    padding: 15,
    margin: 12,
    borderRadius: 8,
    alignItems: 'center',
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '600',
  },
});

3. Styling with StyleSheet

React Native uses JavaScript objects for styling, similar to CSS but with camelCase properties. The StyleSheet API optimizes styles for better performance.

Flexbox Layouts

import { View, Text, StyleSheet } from 'react-native';

function FlexboxExample() {
  return (
    <View style={styles.container}>
      {/* Row layout */}
      <View style={styles.row}>
        <View style={[styles.box, { backgroundColor: '#FF6B6B' }]}>
          <Text style={styles.boxText}>1</Text>
        </View>
        <View style={[styles.box, { backgroundColor: '#4ECDC4' }]}>
          <Text style={styles.boxText}>2</Text>
        </View>
        <View style={[styles.box, { backgroundColor: '#45B7D1' }]}>
          <Text style={styles.boxText}>3</Text>
        </View>
      </View>

      {/* Column layout */}
      <View style={styles.column}>
        <View style={[styles.box, { backgroundColor: '#FFA07A' }]}>
          <Text style={styles.boxText}>A</Text>
        </View>
        <View style={[styles.box, { backgroundColor: '#98D8C8' }]}>
          <Text style={styles.boxText}>B</Text>
        </View>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  row: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    marginBottom: 20,
  },
  column: {
    flexDirection: 'column',
    alignItems: 'center',
  },
  box: {
    width: 80,
    height: 80,
    justifyContent: 'center',
    alignItems: 'center',
    borderRadius: 10,
    margin: 5,
  },
  boxText: {
    color: '#fff',
    fontSize: 24,
    fontWeight: 'bold',
  },
});

4. Navigation

React Navigation Setup

# Install navigation libraries
npm install @react-navigation/native
npm install @react-navigation/native-stack
npm install react-native-screens react-native-safe-area-context

// App.tsx
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { View, Text, Button, StyleSheet } from 'react-native';

const Stack = createNativeStackNavigator();

function HomeScreen({ navigation }) {
  return (
    <View style={styles.screen}>
      <Text style={styles.title}>Home Screen</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Details', {
          itemId: 86,
          itemName: 'React Native'
        })}
      />
    </View>
  );
}

function DetailsScreen({ route, navigation }) {
  const { itemId, itemName } = route.params;

  return (
    <View style={styles.screen}>
      <Text style={styles.title}>Details Screen</Text>
      <Text>Item ID: {itemId}</Text>
      <Text>Item Name: {itemName}</Text>
      <Button
        title="Go Back"
        onPress={() => navigation.goBack()}
      />
      <Button
        title="Go to Home"
        onPress={() => navigation.navigate('Home')}
      />
    </View>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator
        initialRouteName="Home"
        screenOptions={{
          headerStyle: { backgroundColor: '#007AFF' },
          headerTintColor: '#fff',
          headerTitleStyle: { fontWeight: 'bold' },
        }}
      >
        <Stack.Screen 
          name="Home" 
          component={HomeScreen}
          options={{ title: 'My Home' }}
        />
        <Stack.Screen 
          name="Details" 
          component={DetailsScreen}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

const styles = StyleSheet.create({
  screen: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
});

5. Fetching Data & State Management

API Integration

import React, { useState, useEffect } from 'react';
import {
  View,
  Text,
  FlatList,
  ActivityIndicator,
  StyleSheet,
  TouchableOpacity
} from 'react-native';

interface User {
  id: number;
  name: string;
  email: string;
}

function UserListScreen() {
  const [users, setUsers] = useState<User[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    fetchUsers();
  }, []);

  const fetchUsers = async () => {
    try {
      setLoading(true);
      const response = await fetch('https://jsonplaceholder.typicode.com/users');
      if (!response.ok) throw new Error('Failed to fetch');
      const data = await response.json();
      setUsers(data);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  if (loading) {
    return (
      <View style={styles.center}>
        <ActivityIndicator size="large" color="#007AFF" />
      </View>
    );
  }

  if (error) {
    return (
      <View style={styles.center}>
        <Text style={styles.error}>Error: {error}</Text>
        <TouchableOpacity style={styles.button} onPress={fetchUsers}>
          <Text style={styles.buttonText}>Retry</Text>
        </TouchableOpacity>
      </View>
    );
  }

  return (
    <FlatList
      data={users}
      keyExtractor={(item) => item.id.toString()}
      renderItem={({ item }) => (
        <View style={styles.userCard}>
          <Text style={styles.userName}>{item.name}</Text>
          <Text style={styles.userEmail}>{item.email}</Text>
        </View>
      )}
      refreshing={loading}
      onRefresh={fetchUsers}
    />
  );
}

const styles = StyleSheet.create({
  center: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  userCard: {
    padding: 15,
    marginHorizontal: 10,
    marginVertical: 5,
    backgroundColor: '#fff',
    borderRadius: 8,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  userName: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 5,
  },
  userEmail: {
    fontSize: 14,
    color: '#666',
  },
  error: {
    color: 'red',
    marginBottom: 20,
  },
  button: {
    backgroundColor: '#007AFF',
    padding: 15,
    borderRadius: 8,
  },
  buttonText: {
    color: '#fff',
    fontWeight: '600',
  },
});

export default UserListScreen;

6. Local Storage

AsyncStorage

# Install AsyncStorage
npm install @react-native-async-storage/async-storage

import AsyncStorage from '@react-native-async-storage/async-storage';
import React, { useState, useEffect } from 'react';
import { View, TextInput, Button, Text, StyleSheet } from 'react-native';

function SettingsScreen() {
  const [username, setUsername] = useState('');
  const [savedUsername, setSavedUsername] = useState('');

  useEffect(() => {
    loadUsername();
  }, []);

  const loadUsername = async () => {
    try {
      const value = await AsyncStorage.getItem('username');
      if (value !== null) {
        setSavedUsername(value);
        setUsername(value);
      }
    } catch (error) {
      console.error('Error loading data:', error);
    }
  };

  const saveUsername = async () => {
    try {
      await AsyncStorage.setItem('username', username);
      setSavedUsername(username);
      alert('Username saved!');
    } catch (error) {
      console.error('Error saving data:', error);
    }
  };

  const clearUsername = async () => {
    try {
      await AsyncStorage.removeItem('username');
      setUsername('');
      setSavedUsername('');
      alert('Username cleared!');
    } catch (error) {
      console.error('Error clearing data:', error);
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.label}>Username:</Text>
      <TextInput
        style={styles.input}
        value={username}
        onChangeText={setUsername}
        placeholder="Enter username"
      />
      <Button title="Save" onPress={saveUsername} />
      <Button title="Clear" onPress={clearUsername} color="red" />
      
      {savedUsername && (
        <Text style={styles.saved}>
          Saved: {savedUsername}
        </Text>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  label: {
    fontSize: 18,
    marginBottom: 10,
  },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    padding: 10,
    borderRadius: 5,
    marginBottom: 20,
  },
  saved: {
    marginTop: 20,
    fontSize: 16,
    color: 'green',
  },
});

export default SettingsScreen;

Key Takeaways

  • React Native uses native components, not web views
  • Flexbox is the primary layout system
  • StyleSheet optimizes styles for performance
  • React Navigation handles screen transitions
  • AsyncStorage persists data locally
  • Test on both iOS and Android regularly

Practice Projects

Build These Apps

  1. 1. Weather App: Fetch weather data from an API and display forecasts.
  2. 2. Todo List: Create, update, delete tasks with local storage.
  3. 3. News Reader: Display articles from a news API with categories.
  4. 4. Expense Tracker: Track income/expenses with charts and categories.

Continue Learning

Next: Advanced React Native

Learn animations, native modules, and performance optimization.

Practice Coding

Build your skills with interactive challenges.