Bootcamp
React Native one-day bootcamp: Expo setup, screens, navigation, data, persistence, build for stores.
React Native — bootcamp
EXAMPLE
# ===== 0-30 min: scaffold =====
npx create-expo-app my-app
cd my-app
npx expo start
# Press 'a' for Android emulator, 'i' for iOS simulator, or scan QR with Expo Go on a phone.
# Project uses expo-router (file-based routing) by default.
# ===== 30-60 min: tabs + screens =====
# app/(tabs)/_layout.tsx already configures tabs.
# Add a screen:
# app/(tabs)/about.tsx
import { View, Text } from 'react-native';
export default function About() {
return <View><Text>About</Text></View>;
}
# Add to _layout.tsx:
<Tabs.Screen name="about" options={{ title: 'About' }} />
# ===== 60-120 min: a real screen with state + data =====
# app/(tabs)/users.tsx
import { useState, useEffect } from 'react';
import { FlatList, Text, View, ActivityIndicator } from 'react-native';
export default function Users() {
const [data, setData] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then(r => r.json())
.then(setData)
.finally(() => setLoading(false));
}, []);
if (loading) return <ActivityIndicator />;
return (
<FlatList
data={data}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<View style={{ padding: 12 }}><Text>{item.name}</Text></View>
)}
/>
);
}
# ===== 120-180 min: form + validation =====
npm install react-hook-form zod @hookform/resolvers
# app/login.tsx
import { useForm, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { View, TextInput, Pressable, Text } from 'react-native';
const schema = z.object({ email: z.string().email(), password: z.string().min(8) });
type FormData = z.infer<typeof schema>;
export default function Login() {
const { control, handleSubmit, formState: { errors } } = useForm<FormData>({ resolver: zodResolver(schema) });
return (
<View style={{ padding: 16, gap: 12 }}>
<Controller control={control} name="email"
render={({ field: { onChange, value } }) => (
<TextInput value={value} onChangeText={onChange} placeholder="Email" autoCapitalize="none" />
)}
/>
{errors.email && <Text>{errors.email.message}</Text>}
<Pressable onPress={handleSubmit((d) => console.log(d))}><Text>Sign in</Text></Pressable>
</View>
);
}
# ===== 180-240 min: persistence =====
npx expo install @react-native-async-storage/async-storage
# or for fast key-value:
npx expo install react-native-mmkv
import AsyncStorage from '@react-native-async-storage/async-storage';
await AsyncStorage.setItem('theme', 'dark');
const theme = await AsyncStorage.getItem('theme');
# ===== 240-300 min: native APIs =====
npx expo install expo-location expo-camera expo-haptics
import * as Location from 'expo-location';
const { status } = await Location.requestForegroundPermissionsAsync();
if (status === 'granted') {
const pos = await Location.getCurrentPositionAsync();
console.log(pos.coords);
}
# ===== 300-360 min: testing =====
npx expo install jest jest-expo react-test-renderer @testing-library/react-native
# package.json scripts:
"test": "jest --watch"
# __tests__/Counter.test.tsx
import { render, fireEvent } from '@testing-library/react-native';
test('counter increments', () => {
const { getByText } = render(<Counter />);
fireEvent.press(getByText('+1'));
expect(getByText('1')).toBeTruthy();
});
# ===== 360-420 min: build for stores =====
npm install -g eas-cli
eas login
eas build:configure
eas build --platform ios
eas build --platform android
# Submit:
eas submit --platform ios
eas submit --platform android
# OTA updates (skip store review for JS-only changes):
eas update --branch production --message 'small fix'
# ===== Patterns =====
# - Expo + EAS in 2026
# - expo-router for file-based navigation
# - FlatList for any non-trivial list
# - AsyncStorage / MMKV for small persistence
# - Permission gates before native APIs
# ===== Pitfalls =====
# - Strings outside <Text> -> crash
# - ScrollView for long lists -> jank
# - Permissions called before user understanding
# - Storage keys colliding across features
Why it matters
A one-day RN bootcamp: Expo scaffold, tabs + screens, FlatList + fetch, form + validation, AsyncStorage, native APIs with permissions, tests, EAS build + submit + OTA. Same shape ships most production apps in 2026.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…