install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/TerminalSkills/skills/react-native-expo" ~/.claude/skills/comeonoliver-skillshub-react-native-expo && rm -rf "$T"
manifest:
skills/TerminalSkills/skills/react-native-expo/SKILL.mdsource content
React Native with Expo — Modern Mobile Development
You are an expert in React Native with Expo, the modern framework for building native iOS and Android apps with React. You help developers create mobile applications using Expo Router (file-based navigation), Expo SDK modules (camera, notifications, auth, maps), EAS Build/Submit for cloud builds, over-the-air updates, and the full Expo development workflow — from
npx create-expo-app to App Store submission.
Core Capabilities
File-Based Navigation (Expo Router)
// app/_layout.tsx — Root layout with tab navigation import { Tabs } from "expo-router"; import { Ionicons } from "@expo/vector-icons"; export default function Layout() { return ( <Tabs screenOptions={{ tabBarActiveTintColor: "#007AFF" }}> <Tabs.Screen name="index" options={{ title: "Home", tabBarIcon: ({ color, size }) => <Ionicons name="home" color={color} size={size} />, }} /> <Tabs.Screen name="explore" options={{ title: "Explore", tabBarIcon: ({ color, size }) => <Ionicons name="compass" color={color} size={size} />, }} /> <Tabs.Screen name="profile" options={{ title: "Profile", tabBarIcon: ({ color, size }) => <Ionicons name="person" color={color} size={size} />, }} /> </Tabs> ); } // app/index.tsx — Home screen import { View, Text, FlatList, Pressable } from "react-native"; import { Link } from "expo-router"; export default function Home() { return ( <View style={{ flex: 1, padding: 16 }}> <Text style={{ fontSize: 24, fontWeight: "bold" }}>Welcome</Text> <Link href="/explore" asChild> <Pressable style={{ padding: 12, backgroundColor: "#007AFF", borderRadius: 8, marginTop: 16 }}> <Text style={{ color: "white", textAlign: "center" }}>Explore</Text> </Pressable> </Link> </View> ); } // app/post/[id].tsx — Dynamic route import { useLocalSearchParams } from "expo-router"; export default function Post() { const { id } = useLocalSearchParams<{ id: string }>(); return <Text>Post #{id}</Text>; }
Expo SDK Modules
// Camera import { CameraView, useCameraPermissions } from "expo-camera"; function CameraScreen() { const [permission, requestPermission] = useCameraPermissions(); const cameraRef = useRef<CameraView>(null); if (!permission?.granted) { return <Button title="Grant Camera Access" onPress={requestPermission} />; } const takePicture = async () => { const photo = await cameraRef.current?.takePictureAsync(); console.log(photo?.uri); }; return <CameraView ref={cameraRef} style={{ flex: 1 }} facing="back" />; } // Push Notifications import * as Notifications from "expo-notifications"; async function registerForPush() { const { status } = await Notifications.requestPermissionsAsync(); if (status !== "granted") return; const token = await Notifications.getExpoPushTokenAsync({ projectId: "your-project-id" }); return token.data; // Send to your backend } // Local notifications await Notifications.scheduleNotificationAsync({ content: { title: "Reminder", body: "Don't forget your task!" }, trigger: { seconds: 3600 }, // 1 hour from now }); // Secure Storage import * as SecureStore from "expo-secure-store"; await SecureStore.setItemAsync("token", "jwt-abc123"); const token = await SecureStore.getItemAsync("token");
EAS Build and Submit
# Install EAS CLI npm install -g eas-cli # Configure build eas build:configure # Build for iOS and Android eas build --platform ios # Cloud build → .ipa eas build --platform android # Cloud build → .aab # Submit to stores eas submit --platform ios # App Store Connect eas submit --platform android # Google Play Console # Over-the-air updates (no store review needed) eas update --branch production --message "Bug fix for login screen"
Installation
npx create-expo-app@latest my-app cd my-app npx expo start # Dev server with QR code # Scan QR with Expo Go app (iOS/Android) for instant preview
Best Practices
- Expo Router — File-based navigation;
directory maps to screens,app/
for dynamic routes[param] - Expo Go for dev — Scan QR code to preview on real device; no Xcode/Android Studio needed for development
- EAS Build — Cloud builds for iOS without a Mac; handles signing, provisioning, and certificates
- OTA updates — Push JS updates instantly via
; skip App Store review for non-native changeseas update - Expo SDK modules — Camera, notifications, maps, auth, haptics; native APIs with JS interface
- Secure storage — Use
for tokens/secrets; encrypted Keychain (iOS) / Keystore (Android)expo-secure-store - Config plugins — Customize native code without ejecting;
for dynamic configurationapp.config.ts - Prebuild — Run
to generate native projects when you need custom native modulesnpx expo prebuild