React Native Essentials Core Components import { View, Text, TextInput, TouchableOpacity, Pressable, ScrollView, FlatList, Image, StyleSheet, Platform, SafeArea…
React Native Essentials
Core Components
import {
View, Text, TextInput, TouchableOpacity, Pressable,
ScrollView, FlatList, Image, StyleSheet, Platform,
SafeAreaView, KeyboardAvoidingView, ActivityIndicator,
} from 'react-native';
// Layout — flexbox by default (column direction)
const styles = StyleSheet.create({
container: {
flex: 1, // fill available space
flexDirection: 'column', // default (unlike web)
backgroundColor: '#fff',
paddingHorizontal: 16,
},
row: { flexDirection: 'row', alignItems: 'center', gap: 8 },
card: {
backgroundColor: '#f9fafb',
borderRadius: 12,
padding: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3, // Android shadow
},
});
// FlatList — performant list (virtualised)
function UserList({ users }: { users: User[] }) {
return (
<FlatList
data={users}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <UserCard user={item} />}
ItemSeparatorComponent={() => <View style={{ height: 8 }} />}
ListEmptyComponent={<Text>No users found</Text>}
onEndReached={loadMore} // pagination
onEndReachedThreshold={0.5}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
/>
);
}
// Platform-specific code
const hitSlop = Platform.select({
ios: { top: 10, bottom: 10, left: 10, right: 10 },
android: { top: 8, bottom: 8, left: 8, right: 8 },
});
Navigation (Expo Router / React Navigation)
// Expo Router (file-based, recommended for new projects)
// app/index.tsx → /
// app/profile.tsx → /profile
// app/users/[id].tsx → /users/:id
// app/(tabs)/home.tsx → tab layout
// app/users/[id].tsx
import { useLocalSearchParams, useRouter } from 'expo-router';
export default function UserScreen() {
const { id } = useLocalSearchParams<{ id: string }>();
const router = useRouter();
return (
<View>
<Text>User {id}</Text>
<Pressable onPress={() => router.back()}>
<Text>Go back</Text>
</Pressable>
<Pressable onPress={() => router.push('/settings')}>
<Text>Settings</Text>
</Pressable>
</View>
);
}
// app/(tabs)/_layout.tsx — tab navigation
import { Tabs } from 'expo-router';
export default function TabLayout() {
return (
<Tabs>
<Tabs.Screen name="home" options={{ title: 'Home', tabBarIcon: ... }} />
<Tabs.Screen name="profile" options={{ title: 'Profile' }} />
</Tabs>
);
}
Hooks & Native APIs
import { useState, useEffect, useCallback } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as SecureStore from 'expo-secure-store';
import * as Haptics from 'expo-haptics';
import { useColorScheme } from 'react-native';
// Persist data
await AsyncStorage.setItem('key', JSON.stringify(data));
const raw = await AsyncStorage.getItem('key');
const data = raw ? JSON.parse(raw) : null;
// Secure storage (keychain / keystore)
await SecureStore.setItemAsync('token', jwtToken);
const token = await SecureStore.getItemAsync('token');
// Haptics feedback
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
// Dark mode
const colorScheme = useColorScheme(); // 'light' | 'dark'
// Custom hook: keyboard height
import { Keyboard, KeyboardEvent } from 'react-native';
function useKeyboardHeight() {
const [height, setHeight] = useState(0);
useEffect(() => {
const show = Keyboard.addListener('keyboardDidShow', (e: KeyboardEvent) =>
setHeight(e.endCoordinates.height)
);
const hide = Keyboard.addListener('keyboardDidHide', () => setHeight(0));
return () => { show.remove(); hide.remove(); };
}, []);
return height;
}