React Native
02 / 02

React Native Essentials

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;
}

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free