
- Introduction
- What is React Native?
- Prerequisites
- Setting Up Your Development Environment
- Creating Your First React Native App
- Running Your App
- Building Your First Screen
- Core React Native Components
- Styling in React Native
- State Management with Hooks
- Navigation Between Screens
- Working with APIs and Data Fetching
- Debugging Your React Native App
- Common Challenges and Solutions
- Performance Optimization Tips
- Testing Your React Native App
- Publishing Your App
- Bonus: Adding Local Storage
- Next Steps and Resources
- Conclusion
Introduction
React Native has revolutionized mobile app development by allowing developers to build native mobile applications using JavaScript and React. Whether you’re a web developer looking to expand into mobile development or a complete beginner, this comprehensive guide will walk you through creating your first React Native app from scratch.
What is React Native?
React Native is an open-source framework developed by Meta (formerly Facebook) that enables developers to build mobile applications for both iOS and Android platforms using a single codebase. Unlike hybrid frameworks that render web views, React Native compiles to native components, providing near-native performance and user experience.
Key Benefits of React Native
Cross-Platform Development: Write once, deploy to both iOS and Android, significantly reducing development time and costs.
Faster Development: Hot reloading allows you to see changes instantly without rebuilding your entire app.
Large Community: Access to thousands of third-party libraries and a supportive developer community.
Cost-Effective: Maintain one codebase instead of separate iOS and Android teams.
Native Performance: Components compile to native code, ensuring smooth animations and responsive interfaces.
Prerequisites
Before starting this tutorial, you should have:
- Basic understanding of JavaScript and ES6+ features
- Familiarity with React concepts (components, props, state, hooks)
- Node.js installed (version 18 or newer recommended)
- A code editor (VS Code is highly recommended)
- For iOS development: A Mac with Xcode installed
- For Android development: Android Studio installed
Setting Up Your Development Environment
Installing Node.js and npm
Download and install the latest LTS version of Node.js from the official website. This will also install npm (Node Package Manager), which you’ll use to install React Native and other dependencies.
Verify your installation by opening a terminal and running:
node --version
npm --version
Installing React Native CLI
While Expo is a popular option for beginners, we’ll use React Native CLI for this tutorial as it provides more flexibility and access to native code.
Install the React Native CLI globally:
npm install -g react-native-cli
Setting Up Android Studio
Download and install Android Studio, then configure the Android SDK. Open Android Studio, go to Preferences, navigate to Appearance & Behavior, then System Settings, and finally Android SDK. Install Android SDK Platform 34 (or the latest version) and configure the ANDROID_HOME environment variable.
Setting Up Xcode (Mac Only)
Install Xcode from the Mac App Store, then install the Xcode Command Line Tools by running:
xcode-select --install
Also install CocoaPods, which manages dependencies for iOS projects:
sudo gem install cocoapods
Creating Your First React Native App
Initialize a New Project
Open your terminal and navigate to the directory where you want to create your project. Run:
npx react-native init MyFirstApp
This command creates a new React Native project with all necessary files and dependencies. The process may take several minutes as it downloads and installs required packages.
Understanding the Project Structure
Once created, your project directory will contain several important folders and files:
android/ – Contains the Android native code and configuration ios/ – Contains the iOS native code and configuration node_modules/ – All npm dependencies App.js – The main React component (your starting point) package.json – Project metadata and dependencies index.js – Entry point of your application
Running Your App
On iOS Simulator
Navigate to your project directory and run:
cd MyFirstApp
npx react-native run-ios
This builds your app and launches it in the iOS Simulator. The first build may take several minutes.
On Android Emulator
First, launch an Android emulator from Android Studio or use a connected Android device with USB debugging enabled. Then run:
npx react-native run-android
The app will build and install on your Android device or emulator.
Building Your First Screen
Let’s create a simple but functional app that demonstrates core React Native concepts. We’ll build a counter app with increment and decrement functionality.
Creating the Basic Layout
Open App.js and replace its contents with this code:
import React, { useState } from 'react';
import {
SafeAreaView,
View,
Text,
TouchableOpacity,
StyleSheet,
StatusBar,
} from 'react-native';
const App = () => {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
const decrement = () => {
setCount(count - 1);
};
const reset = () => {
setCount(0);
};
return (
<SafeAreaView style={styles.container}>
<StatusBar barStyle="light-content" />
<View style={styles.content}>
<Text style={styles.title}>My First React Native App</Text>
<Text style={styles.subtitle}>Counter Application</Text>
<View style={styles.counterContainer}>
<Text style={styles.counterText}>{count}</Text>
</View>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={[styles.button, styles.decrementButton]}
onPress={decrement}
>
<Text style={styles.buttonText}>−</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.button, styles.resetButton]}
onPress={reset}
>
<Text style={styles.buttonText}>Reset</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.button, styles.incrementButton]}
onPress={increment}
>
<Text style={styles.buttonText}>+</Text>
</TouchableOpacity>
</View>
<View style={styles.infoContainer}>
<Text style={styles.infoText}>
{count === 0 && "Start counting!"}
{count > 0 && `You've counted up ${count} times`}
{count < 0 && `You've counted down ${Math.abs(count)} times`}
</Text>
</View>
</View>
</SafeAreaView>
);
};
export default App;
Adding Styling
Create comprehensive styles at the bottom of your App.js file:
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#1a1a2e',
},
content: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 28,
fontWeight: 'bold',
color: '#eee',
marginBottom: 8,
textAlign: 'center',
},
subtitle: {
fontSize: 16,
color: '#16db93',
marginBottom: 50,
textAlign: 'center',
},
counterContainer: {
backgroundColor: '#0f3460',
borderRadius: 20,
padding: 40,
marginBottom: 40,
minWidth: 200,
alignItems: 'center',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 4,
},
shadowOpacity: 0.3,
shadowRadius: 4.65,
elevation: 8,
},
counterText: {
fontSize: 72,
fontWeight: 'bold',
color: '#16db93',
},
buttonContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
maxWidth: 400,
marginBottom: 30,
},
button: {
paddingVertical: 15,
paddingHorizontal: 20,
borderRadius: 12,
minWidth: 80,
alignItems: 'center',
justifyContent: 'center',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
incrementButton: {
backgroundColor: '#16db93',
},
decrementButton: {
backgroundColor: '#e94560',
},
resetButton: {
backgroundColor: '#533483',
paddingHorizontal: 25,
},
buttonText: {
color: '#fff',
fontSize: 24,
fontWeight: 'bold',
},
infoContainer: {
marginTop: 20,
padding: 15,
backgroundColor: 'rgba(255, 255, 255, 0.1)',
borderRadius: 10,
minWidth: 250,
},
infoText: {
color: '#eee',
fontSize: 16,
textAlign: 'center',
},
});
This creates a modern, attractive interface with:
- Dark theme with vibrant accent colors
- Shadow effects for depth
- Responsive button layout
- Dynamic feedback text
- Professional spacing and typography
Core React Native Components
View
The View component is the fundamental building block, similar to a div in web development. It’s a container that supports layout, styling, and touch handling. Use it to structure your UI and create layouts with flexbox.
Text
All text must be wrapped in a Text component. You can nest Text components and apply different styles to each. Text components support various props like numberOfLines for truncation and onPress for making text interactive.
Image
Display local or remote images using the Image component. For local images, use require(), and for remote images, pass a source object with a uri property. Always specify dimensions for images to prevent layout issues.
ScrollView
When your content exceeds the screen size, wrap it in a ScrollView to enable scrolling. ScrollView renders all its children at once, making it suitable for shorter lists. For long lists, use FlatList instead for better performance.
TextInput
Capture user input with TextInput components. They support various props like placeholder, value, onChangeText, secureTextEntry for passwords, and keyboardType for optimizing the keyboard layout.
TouchableOpacity
Create touchable elements that respond to user presses. TouchableOpacity provides visual feedback by reducing opacity when pressed. It’s perfect for buttons and interactive elements.
Styling in React Native
StyleSheet API
React Native provides the StyleSheet API for defining styles. This approach is more performant than inline styles and provides validation. Create styles using StyleSheet.create() and reference them in your components.
Flexbox Layout
React Native uses flexbox for layouts by default. The flex property determines how components grow or shrink to fill available space. Common flexbox properties include flexDirection (row or column), justifyContent (alignment along main axis), and alignItems (alignment along cross axis).
Dimensions and Responsive Design
Access device dimensions using the Dimensions API. However, for responsive layouts, prefer using flex values and percentages rather than fixed pixel values. This ensures your app looks good on different screen sizes.
State Management with Hooks
useState
The useState hook allows functional components to have state. It returns an array with the current state value and a function to update it. Use useState for simple component-level state management.
useEffect
The useEffect hook handles side effects like data fetching, subscriptions, or manual DOM manipulations. It runs after every render by default, but you can control when it runs using the dependency array.
Custom Hooks
Create custom hooks to extract and reuse stateful logic across components. Custom hooks are JavaScript functions that can call other hooks and return values or functions to the component.
Navigation Between Screens
Most apps have multiple screens. React Navigation is the most popular navigation library for React Native.
Installing React Navigation
Install the core navigation library and its dependencies:
npm install @react-navigation/native
npm install react-native-screens react-native-safe-area-context
For iOS, also install pods:
cd ios && pod install && cd ..
Creating a Stack Navigator
Stack navigation provides transitions between screens where each new screen is placed on top of a stack. Here’s a complete example:
First, install the stack navigator:
npm install @react-navigation/native-stack
Then create a new file screens/HomeScreen.js:
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
const HomeScreen = ({ navigation }) => {
return (
<View style={styles.container}>
<Text style={styles.title}>Welcome to My App!</Text>
<TouchableOpacity
style={styles.button}
onPress={() => navigation.navigate('Details', {
itemId: 86,
itemName: 'Sample Item'
})}
>
<Text style={styles.buttonText}>Go to Details</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#1a1a2e',
},
title: {
fontSize: 24,
color: '#eee',
marginBottom: 20,
},
button: {
backgroundColor: '#16db93',
paddingVertical: 12,
paddingHorizontal: 30,
borderRadius: 8,
},
buttonText: {
color: '#fff',
fontSize: 18,
fontWeight: 'bold',
},
});
export default HomeScreen;
Create screens/DetailsScreen.js:
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
const DetailsScreen = ({ route, navigation }) => {
const { itemId, itemName } = route.params;
return (
<View style={styles.container}>
<Text style={styles.title}>Details Screen</Text>
<Text style={styles.text}>Item ID: {itemId}</Text>
<Text style={styles.text}>Item Name: {itemName}</Text>
<TouchableOpacity
style={styles.button}
onPress={() => navigation.goBack()}
>
<Text style={styles.buttonText}>Go Back</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.button, styles.homeButton]}
onPress={() => navigation.navigate('Home')}
>
<Text style={styles.buttonText}>Go to Home</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#1a1a2e',
},
title: {
fontSize: 24,
color: '#eee',
marginBottom: 20,
},
text: {
fontSize: 18,
color: '#16db93',
marginBottom: 10,
},
button: {
backgroundColor: '#16db93',
paddingVertical: 12,
paddingHorizontal: 30,
borderRadius: 8,
marginTop: 15,
},
homeButton: {
backgroundColor: '#533483',
},
buttonText: {
color: '#fff',
fontSize: 18,
fontWeight: 'bold',
},
});
export default DetailsScreen;
Update your App.js to use navigation:
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import HomeScreen from './screens/HomeScreen';
import DetailsScreen from './screens/DetailsScreen';
const Stack = createNativeStackNavigator();
const App = () => {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
headerStyle: {
backgroundColor: '#0f3460',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'My App' }}
/>
<Stack.Screen
name="Details"
component={DetailsScreen}
options={{ title: 'Item Details' }}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
Navigating Between Screens
Use the navigation prop passed to each screen component. Call navigation.navigate(‘ScreenName’) to push a new screen, navigation.goBack() to return to the previous screen, and pass parameters between screens using the route prop.
Working with APIs and Data Fetching
Using Fetch API
React Native supports the Fetch API for making HTTP requests. Here’s a complete example fetching data from a public API:
Create a new file screens/UsersScreen.js:
import React, { useState, useEffect } from 'react';
import {
View,
Text,
FlatList,
ActivityIndicator,
StyleSheet,
TouchableOpacity,
} from 'react-native';
const UsersScreen = () => {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [refreshing, setRefreshing] = useState(false);
const fetchUsers = async () => {
try {
setError(null);
const response = await fetch('https://jsonplaceholder.typicode.com/users');
if (!response.ok) {
throw new Error('Failed to fetch users');
}
const data = await response.json();
setUsers(data);
} catch (err) {
setError(err.message);
console.error('Error fetching users:', err);
} finally {
setLoading(false);
setRefreshing(false);
}
};
useEffect(() => {
fetchUsers();
}, []);
const onRefresh = () => {
setRefreshing(true);
fetchUsers();
};
const renderUser = ({ item }) => (
<View style={styles.userCard}>
<Text style={styles.userName}>{item.name}</Text>
<Text style={styles.userEmail}>{item.email}</Text>
<Text style={styles.userPhone}>{item.phone}</Text>
<Text style={styles.userWebsite}>{item.website}</Text>
</View>
);
if (loading) {
return (
<View style={styles.centerContainer}>
<ActivityIndicator size="large" color="#16db93" />
<Text style={styles.loadingText}>Loading users...</Text>
</View>
);
}
if (error) {
return (
<View style={styles.centerContainer}>
<Text style={styles.errorText}>Error: {error}</Text>
<TouchableOpacity style={styles.retryButton} onPress={fetchUsers}>
<Text style={styles.retryButtonText}>Retry</Text>
</TouchableOpacity>
</View>
);
}
return (
<View style={styles.container}>
<FlatList
data={users}
renderItem={renderUser}
keyExtractor={item => item.id.toString()}
contentContainerStyle={styles.listContainer}
refreshing={refreshing}
onRefresh={onRefresh}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#1a1a2e',
},
centerContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#1a1a2e',
},
listContainer: {
padding: 16,
},
userCard: {
backgroundColor: '#0f3460',
borderRadius: 12,
padding: 16,
marginBottom: 12,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
userName: {
fontSize: 18,
fontWeight: 'bold',
color: '#16db93',
marginBottom: 6,
},
userEmail: {
fontSize: 14,
color: '#eee',
marginBottom: 4,
},
userPhone: {
fontSize: 14,
color: '#aaa',
marginBottom: 4,
},
userWebsite: {
fontSize: 14,
color: '#533483',
},
loadingText: {
marginTop: 12,
fontSize: 16,
color: '#eee',
},
errorText: {
fontSize: 16,
color: '#e94560',
textAlign: 'center',
marginBottom: 20,
paddingHorizontal: 20,
},
retryButton: {
backgroundColor: '#16db93',
paddingVertical: 12,
paddingHorizontal: 30,
borderRadius: 8,
},
retryButtonText: {
color: '#fff',
fontSize: 16,
fontWeight: 'bold',
},
});
export default UsersScreen;
Async/Await Pattern
The code above demonstrates best practices for API calls:
- Loading State: Shows an ActivityIndicator while fetching data
- Error Handling: Catches and displays errors with a retry option
- Pull to Refresh: Allows users to manually refresh the data
- FlatList Performance: Efficiently renders lists with built-in optimization
- Clean Async Code: Uses async/await for readable asynchronous operations
Debugging Your React Native App
React Native Debugger
Access the developer menu by shaking your device or pressing Cmd+D (iOS) or Cmd+M (Android) in the emulator. Enable “Debug JS Remotely” to use Chrome DevTools for debugging.
Console Logging
Use console.log(), console.warn(), and console.error() to output debugging information. These messages appear in the Metro Bundler terminal and in the debugging console.
React DevTools
Install the standalone React DevTools to inspect your component hierarchy, props, and state. It provides insights into component updates and helps identify performance issues.
Common Challenges and Solutions
Metro Bundler Issues
If the Metro Bundler fails to start or shows caching issues, try clearing the cache with npx react-native start --reset-cache. Also ensure no other process is using port 8081.
Build Failures
For Android build issues, try cleaning the build folder with cd android && ./gradlew clean. For iOS issues, clean the build in Xcode or delete the ios/build folder and Pods, then reinstall with pod install.
Version Conflicts
Keep React Native and related dependencies compatible. Check the React Native upgrade helper website when upgrading versions. Mismatched versions between packages often cause build errors.
Performance Optimization Tips
Use FlatList for Long Lists
Replace ScrollView with FlatList when rendering long lists. FlatList only renders items currently visible on screen, significantly improving performance with large datasets.
Optimize Images
Compress images before adding them to your app. Use appropriate image formats (WebP for best compression) and sizes. For remote images, implement caching strategies.
Avoid Inline Functions
Define functions outside your render method rather than creating them inline. Inline functions create new instances on each render, potentially causing unnecessary re-renders of child components.
Use PureComponent or React.memo
Wrap functional components with React.memo or use PureComponent for class components to prevent unnecessary re-renders when props haven’t changed.
Testing Your React Native App
Unit Testing with Jest
React Native comes with Jest configured out of the box. Create a test file tests/App.test.js:
import React from 'react';
import { render, fireEvent } from '@testing-library/react-native';
import App from '../App';
describe('Counter App', () => {
it('renders correctly', () => {
const { getByText } = render(<App />);
expect(getByText('My First React Native App')).toBeTruthy();
});
it('increments counter when + button is pressed', () => {
const { getByText } = render(<App />);
const incrementButton = getByText('+');
fireEvent.press(incrementButton);
expect(getByText('1')).toBeTruthy();
fireEvent.press(incrementButton);
expect(getByText('2')).toBeTruthy();
});
it('decrements counter when - button is pressed', () => {
const { getByText } = render(<App />);
const decrementButton = getByText('−');
fireEvent.press(decrementButton);
expect(getByText('-1')).toBeTruthy();
});
it('resets counter when Reset button is pressed', () => {
const { getByText } = render(<App />);
const incrementButton = getByText('+');
const resetButton = getByText('Reset');
fireEvent.press(incrementButton);
fireEvent.press(incrementButton);
fireEvent.press(resetButton);
expect(getByText('0')).toBeTruthy();
});
});
Install testing library:
npm install --save-dev @testing-library/react-native
Run tests with:
npm test
Component Testing with Testing Library
Use React Native Testing Library to test components from the user’s perspective. It encourages best practices by testing what users see and interact with rather than internal component state.
Publishing Your App
Preparing for Production
Before publishing, update your app name, bundle identifier, version number, and icons. Test thoroughly on real devices, optimize bundle size, and ensure all permissions are properly configured.
Building for iOS
Create a production build in Xcode:
- Open your project in Xcode:
cd ios
open YourAppName.xcworkspace
- Select “Any iOS Device” as the build target
- Go to Product → Archive
- Once archived, click “Distribute App”
- Choose “App Store Connect” or “Ad Hoc” for testing
- Follow the prompts to sign and upload
Update version in ios/YourAppName/Info.plist:
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleVersion</key>
<string>1</string>
Building for Android
Generate a signed APK or Android App Bundle:
- Generate a signing key (first time only):
cd android/app
keytool -genkeypair -v -storetype PKCS12 -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
- Edit android/gradle.properties and add:
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=*****
MYAPP_RELEASE_KEY_PASSWORD=*****
- Edit android/app/build.gradle:
android {
...
signingConfigs {
release {
if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
}
buildTypes {
release {
...
signingConfig signingConfigs.release
}
}
}
- Build the release APK:
cd android
./gradlew assembleRelease
The APK will be at: android/app/build/outputs/apk/release/app-release.apk
For App Bundle (recommended for Play Store):
./gradlew bundleRelease
Update version in android/app/build.gradle:
android {
defaultConfig {
versionCode 1
versionName "1.0.0"
}
}
Bonus: Adding Local Storage
Let’s add persistent storage to our counter app using AsyncStorage:
Install AsyncStorage:
npm install @react-native-async-storage/async-storage
Update your counter app in App.js:
import React, { useState, useEffect } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {
SafeAreaView,
View,
Text,
TouchableOpacity,
StyleSheet,
StatusBar,
} from 'react-native';
const STORAGE_KEY = '@counter_value';
const App = () => {
const [count, setCount] = useState(0);
const [loading, setLoading] = useState(true);
// Load saved count on app start
useEffect(() => {
loadCount();
}, []);
// Save count whenever it changes
useEffect(() => {
if (!loading) {
saveCount(count);
}
}, [count]);
const loadCount = async () => {
try {
const savedCount = await AsyncStorage.getItem(STORAGE_KEY);
if (savedCount !== null) {
setCount(parseInt(savedCount, 10));
}
} catch (error) {
console.error('Error loading count:', error);
} finally {
setLoading(false);
}
};
const saveCount = async (value) => {
try {
await AsyncStorage.setItem(STORAGE_KEY, value.toString());
} catch (error) {
console.error('Error saving count:', error);
}
};
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
const reset = async () => {
setCount(0);
try {
await AsyncStorage.removeItem(STORAGE_KEY);
} catch (error) {
console.error('Error clearing storage:', error);
}
};
if (loading) {
return (
<View style={styles.loadingContainer}>
<Text style={styles.loadingText}>Loading...</Text>
</View>
);
}
return (
<SafeAreaView style={styles.container}>
<StatusBar barStyle="light-content" />
<View style={styles.content}>
<Text style={styles.title}>Persistent Counter</Text>
<Text style={styles.subtitle}>Your count is saved automatically</Text>
<View style={styles.counterContainer}>
<Text style={styles.counterText}>{count}</Text>
</View>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={[styles.button, styles.decrementButton]}
onPress={decrement}
>
<Text style={styles.buttonText}>−</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.button, styles.resetButton]}
onPress={reset}
>
<Text style={styles.buttonText}>Reset</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.button, styles.incrementButton]}
onPress={increment}
>
<Text style={styles.buttonText}>+</Text>
</TouchableOpacity>
</View>
<View style={styles.infoContainer}>
<Text style={styles.infoText}>
💾 Count persists between app restarts
</Text>
</View>
</View>
</SafeAreaView>
);
};
// ... (keep the same styles from earlier)
export default App;
Now your counter value persists even when you close and reopen the app!
Next Steps and Resources
Now that you’ve built your first React Native app, continue learning by exploring more advanced topics like animations, gesture handling, native modules, and offline storage with AsyncStorage or databases.
Recommended Learning Resources
Explore the official React Native documentation, which is comprehensive and regularly updated. Join the React Native community on Discord and Reddit. Build small projects to reinforce your learning. Consider learning TypeScript for better type safety in larger projects.
Popular React Native Libraries
Familiarize yourself with commonly used libraries like React Navigation for routing, Redux or Zustand for state management, Axios for HTTP requests, React Native Paper or Native Base for UI components, and AsyncStorage for local data persistence.
Conclusion
React Native empowers developers to create powerful, cross-platform mobile applications using familiar web technologies. This tutorial covered the fundamentals from setup to building your first app. The key to mastering React Native is consistent practice and building real projects.
Start with simple apps and gradually tackle more complex challenges. The React Native ecosystem is vast and constantly evolving, offering solutions for virtually any mobile app requirement. With the foundation you’ve built today, you’re well-equipped to continue your mobile development journey.
Remember that every expert was once a beginner. Embrace challenges as learning opportunities, leverage the supportive React Native community, and most importantly, keep building. Your first app is just the beginning of an exciting journey into mobile development.
Happy coding!


