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