React Native Basics
Core components, styling, navigation, platform differences, Expo workflow.
react-nativemobileiosandroid
# React Native Basics
## Create (Expo recommended)
```bash
npx create-expo-app@latest MyApp --template
npx expo start # QR code -> Expo Go app
```
## Core components
```tsx
import { View, Text, TextInput, Image, ScrollView,
FlatList, TouchableOpacity, Pressable,
StyleSheet, Platform, Dimensions } from 'react-native'
// View = div, Text = p/span, Image = img
export default function Screen() {
return (
<ScrollView style={styles.container}>
<Text style={styles.title}>Hello</Text>
<TextInput
placeholder="Type here"
value={text}
onChangeText={setText}
keyboardType="email-address"
autoCapitalize="none"
/>
<Pressable
onPress={handlePress}
style={({ pressed }) => [styles.btn, pressed && styles.pressed]}
>
<Text>Press me</Text>
</Pressable>
</ScrollView>
)
}
```
## StyleSheet (no CSS cascade)
```ts
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#fff', padding: 16 },
title: { fontSize: 24, fontWeight: 'bold', color: '#000' },
btn: { backgroundColor: '#000', padding: 12, borderRadius: 8 },
pressed: { opacity: 0.7 },
})
// Flexbox default: column direction (unlike web's row)
// All dimensions are density-independent pixels (dp)
```
## FlatList (virtualized)
```tsx
<FlatList
data={items}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <ItemCard item={item} />}
numColumns={2}
onEndReached={loadMore}
onEndReachedThreshold={0.5}
ListEmptyComponent={<Text>No items</Text>}
/>
```
## Navigation (Expo Router = file-based)
```tsx
// app/(tabs)/index.tsx -> "/" tab
// app/(tabs)/profile.tsx -> "/profile" tab
// app/post/[id].tsx -> "/post/123"
import { useRouter, useLocalSearchParams } from 'expo-router'
const router = useRouter()
router.push('/profile')
router.push({ pathname: '/post/[id]', params: { id: '123' } })
const { id } = useLocalSearchParams()
```
## Platform differences
```ts
import { Platform } from 'react-native'
const style = { paddingTop: Platform.OS === 'ios' ? 44 : 24 }
Platform.select({ ios: 'iOS value', android: 'Android value', default: 'other' })
// Platform-specific files: Component.ios.tsx, Component.android.tsx
```
## Async storage
```bash
npx expo install @react-native-async-storage/async-storage
```
```ts
await AsyncStorage.setItem('key', JSON.stringify(value))
const raw = await AsyncStorage.getItem('key')
const value = raw ? JSON.parse(raw) : null
```
## Common Expo packages
- `expo-camera` -- camera access
- `expo-location` -- GPS
- `expo-notifications` -- push notifications
- `expo-image-picker` -- photo library
- `expo-haptics` -- vibration feedback
- `expo-secure-store` -- encrypted key-value storeAPI: /api/skills/react-native-basics