Expo Environment Setup and RN Core Components
If you already know HTML, CSS, and React (or Next.js), congratulations—you already have the skills to build native iOS and Android apps!
In the past, building iOS apps required learning Swift and Xcode, while Android development demanded Kotlin and Android Studio. Maintaining two entirely different codebases was a nightmare for independent developers.
React Native (RN) shattered these barriers. It allows you to write logic in JavaScript, while the underlying system automatically compiles this code into truly native mobile components (not just stuffing a webpage into a WebView).
And Expo is the god-tier framework built on top of RN. Just like Next.js for React, Expo handles all the painful low-level configurations, enabling you to see a hot-reloaded app on your phone within minutes!
1. Environment Setup: Just One Command
You don’t need to install dozens of GBs of Xcode or Android Studio. All you need is Node.js!
Open your terminal and run:
# Create a new Expo project
npx create-expo-app@latest my-first-app
# Navigate into the project directory
cd my-first-app
# Start the development server
npm run start
At this point, your terminal will display a giant QR Code.
How to Preview on Your Phone?
- Grab your iPhone or Android phone.
- Search for and download the Expo Go app from the App Store or Google Play.
- For iPhone, simply open the built-in camera and scan the QR Code on your computer screen. For Android, open Expo Go and tap "Scan QR Code."
Magic happens! Your phone screen now shows the prototype of your app. Every time you save changes on your computer, the phone screen updates in less than a second—this is the legendary Hot Reload!
2. Forget HTML Tags! Meet Native Components
In the React Native world, there are no <div>, <span>, or <p> tags because phones don’t understand HTML.
You must import dedicated native components from react-native:
| Web (HTML) | React Native (Mobile) | Purpose |
| :--- | :--- | :--- |
| <div> | <View> | Container, layout block |
| <p> / <h1> / <span> | <Text> | Display all text |
| <button> | <TouchableOpacity> / <Pressable> | Clickable button |
| <img> | <Image> | Display images |
| <input> | <TextInput> | Text input field |
| <div style="overflow: scroll"> | <ScrollView> | Scrollable window |
Let’s rewrite app/index.tsx (or App.js):
import { StyleSheet, Text, View, Image, TouchableOpacity, Alert } from 'react-native';
export default function App() {
const handlePress = () => {
// Alert.alert triggers a native system alert dialog!
Alert.alert("Awesome", "You successfully clicked the button!");
};
return (
<View style={styles.container}>
<Image
source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
style={styles.logo}
/>
<Text style={styles.title}>Hello Vibe Tutor!</Text>
<Text style={styles.subtitle}>This is my first native app 📱</Text>
<TouchableOpacity style={styles.button} onPress={handlePress}>
<Text style={styles.buttonText}>Tap Me</Text>
</TouchableOpacity>
</View>
);
}
3. Forget CSS Classes! Meet StyleSheet
In RN, all styles are defined using JavaScript objects, with Flexbox for layout.
[!WARNING] Layout Pitfalls Warning
- RN’s default
flexDirectioniscolumn(vertical), while web CSS defaults torow(horizontal)!- All dimensions are unitless (no
pxorrem), just plain numbers likewidth: 100.- Some complex CSS properties aren’t supported (e.g.,
box-shadowis split into multiple properties).
Here’s the stylesheet from the example above:
const styles = StyleSheet.create({
container: {
flex: 1, // Takes up the entire screen
backgroundColor: '#fff',
alignItems: 'center', // Horizontal centering
justifyContent: 'center', // Vertical centering
},
logo: {
width: 100,
height: 100,
marginBottom: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#333',
},
subtitle: {
fontSize: 16,
color: '#666',
marginTop: 8,
marginBottom: 32,
},
button: {
backgroundColor: '#3b82f6',
paddingHorizontal: 24,
paddingVertical: 12,
borderRadius: 8,
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: '600',
}
});
[!TIP] Want to use Tailwind CSS?
You absolutely can! By installing theNativeWindpackage, you can write familiar syntax like<View className="flex-1 items-center justify-center bg-white">in RN. This is a huge boon for web developers!
4. SafeAreaView: Saving Your Notch and Dynamic Island
When you run the above code on an iPhone, you might notice text being obscured by the "notch" or the "status bar"!
In mobile development, we must respect the system’s "safe area." Make it a habit to wrap your outermost container with <SafeAreaView>:
import { SafeAreaView } from 'react-native-safe-area-context';
export default function App() {
return (
<SafeAreaView style={{ flex: 1, backgroundColor: 'white' }}>
<View style={styles.container}>
{/* ...content... */}
</View>
</SafeAreaView>
);
}
This way, whether your app runs on an iPhone 14 with a notch or an iPhone 15 Pro with a Dynamic Island, your UI will always be perfectly pushed into the safe viewable area!
In the next chapter, we’ll learn how to build the most critical backbone of an app: Multi-Screen Navigation!
Expo SDK Modules
Expo provides built-in modules for common native features — no native code needed.
Core Modules
| Module | Purpose | Installation |
|--------|---------|-------------|
| Camera | Take photos, scan barcodes | expo-camera |
| Location | GPS coordinates, geocoding | expo-location |
| Notifications | Push and local notifications | expo-notifications |
| Haptics | Vibrate, haptic feedback | expo-haptics |
| File System | Read/write files | expo-file-system |
| SecureStore | Encrypted key-value storage | expo-secure-store |
| Sensors | Accelerometer, gyroscope | expo-sensors |
Example: Camera Usage
import { CameraView, useCameraPermissions } from 'expo-camera';
import { useState } from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';
export default function CameraScreen() {
const [permission, requestPermission] = useCameraPermissions();
const [scanned, setScanned] = useState(false);
if (!permission) {
// Camera permissions are still loading
return <View />;
}
if (!permission.granted) {
return (
<View style={styles.container}>
<Text>We need camera permission to scan barcodes</Text>
<Button onPress={requestPermission} title="Grant Permission" />
</View>
);
}
return (
<CameraView
style={styles.camera}
facing="back"
onBarcodeScanned={scanned ? undefined : (result) => {
setScanned(true);
alert(`Barcode: ${result.data}`);
}}
>
<Button title="Scan Again" onPress={() => setScanned(false)} />
</CameraView>
);
}
Expo EAS Build
EAS (Expo Application Services) builds your app in the cloud — no local Xcode or Android Studio needed.
EAS Build Profiles
{
"cli": {
"version": ">= 3.0"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"android": {
"buildType": "apk"
},
"ios": {
"simulator": true
}
},
"production": {}
}
}
Build Commands
# Install EAS CLI
npm install -g eas-cli
# Login to Expo
npx eas login
# Development build (testing)
eas build --platform ios --profile development
# Production build
eas build --platform android --profile production
Expo Updates (Over-the-Air)
Push updates without going through app store review.
# Publish an update
npx expo export --platform web
npx eas update --branch production --message "Fix login crash"
# Rollback if needed
eas update --branch production --message "Rollback to previous"
| Method | Requires App Store Review | Updates Instantly | |--------|--------------------------|-------------------| | App Store Update | ✅ Yes | ❌ Wait for approval | | EAS Update | ❌ No | ✅ Immediate | | CodePush | ❌ No | ✅ Immediate |
Debugging Tools
React Native DevTools
# Open React Native DevTools
npx react-native-debugger
# Or use Expo's built-in dev menu
# Shake device or press Cmd+D in simulator
Common Debugging Techniques
| Technique | How | Best For | |-----------|-----|----------| | console.log | Print to terminal | Quick checks | | React DevTools | Component tree, state | UI debugging | | Network Inspector | See API calls | API debugging | | Error Boundaries | Catch rendering errors | Production crashes | | Crashlytics | Firebase crash reporting | Production |
Summary
Expo setup involves installing the CLI, creating a project, understanding the file structure, and configuring the dev environment. Expo handles most native complexity so you can focus on building features.
Key takeaways:
npx create-expo-appcreates a new project instantly |- Expo Go: test on real devices without building |
app.json/app.config.jscontrols all configuration |- Expo SDK modules: camera, location, notifications, etc. |
SafeAreaViewhandles notches and Dynamic Island |- EAS Build compiles native binaries in the cloud |
- EAS Update pushes fixes over-the-air instantly |
- React DevTools and Network Inspector aid debugging |
What's Next: React Navigation
The next chapter covers multi-screen navigation with React Navigation.