Skip to content

React Native Reference: Core Components, Styles, Navigation, APIs & Expo

React Native lets you build iOS and Android apps using React. Styles use a subset of CSS via StyleSheet.create() — Flexbox is the default layout system and works like web Flexbox but with a few differences: flexDirection defaults to column (not row), and percentage-based dimensions aren’t supported in all contexts. For new projects, start with Expo — it handles the native build complexity so you can focus on your app. Use bare React Native only if you need maximum native module access.

1. Core Components

View, Text, Image, ScrollView, FlatList, TextInput, TouchableOpacity, and SafeAreaView
import {
  View, Text, Image, ScrollView, FlatList,
  TextInput, TouchableOpacity, Pressable,
  StyleSheet, SafeAreaView, Platform,
} from "react-native";

// View = div, Text = p/span (ALL text must be in Text):
<View style={styles.container}>
  <Text style={styles.title}>Hello React Native</Text>
</View>

// Image:
<Image source={require("./assets/logo.png")} style={{ width: 100, height: 100 }} />
<Image source={{ uri: "https://example.com/photo.jpg" }} style={{ width: 200, height: 200 }} />

// FlatList — virtualized list (use instead of .map() for long lists):
<FlatList
  data={users}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <UserCard user={item} />}
  ListEmptyComponent={<Text>No users found</Text>}
  ListHeaderComponent={<Text style={styles.header}>Users</Text>}
  onEndReached={loadMore}
  onEndReachedThreshold={0.5}   // trigger when 50% from bottom
/>

// TouchableOpacity / Pressable for tappable elements:
<TouchableOpacity onPress={() => navigate("Profile")} activeOpacity={0.7}>
  <Text>View Profile</Text>
</TouchableOpacity>

// Pressable — more control over press states:
<Pressable
  onPress={handlePress}
  style={({ pressed }) => [styles.button, pressed && styles.pressed]}
>
  {({ pressed }) => <Text>{pressed ? "Pressing..." : "Press me"}</Text>}
</Pressable>

// SafeAreaView — respects notch / status bar:
<SafeAreaView style={{ flex: 1 }}>
  <YourApp />
</SafeAreaView>

2. StyleSheet & Flexbox

StyleSheet.create(), Flexbox layout, Platform-specific styles, and dimensions
import { StyleSheet, Platform, Dimensions, useWindowDimensions } from "react-native";

const styles = StyleSheet.create({
  container: {
    flex: 1,                          // fill available space
    flexDirection: "column",          // default (not "row" like web!)
    justifyContent: "center",         // main axis
    alignItems: "center",             // cross axis
    backgroundColor: "#f8fafc",
    padding: 16,
  },
  row: {
    flexDirection: "row",
    gap: 12,                          // RN 0.71+ supports gap
  },
  card: {
    flex: 1,                          // equal width in row
    borderRadius: 8,
    padding: 16,
    backgroundColor: "#fff",
    // Shadow (iOS):
    shadowColor: "#000",
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    // Shadow (Android):
    elevation: 4,
  },
});

// Platform-specific styles:
const platformStyle = {
  ...Platform.select({
    ios:     { fontFamily: "SF Pro Text", paddingTop: 20 },
    android: { fontFamily: "Roboto",     paddingTop: 24 },
    web:     { fontFamily: "system-ui",  paddingTop: 0 },
  }),
};

// Responsive dimensions:
const { width, height } = Dimensions.get("window");
// Or with hook (updates on rotation):
function MyComp() {
  const { width } = useWindowDimensions();
  return <View style={{ width: width * 0.9 }} />;
}

3. Navigation (React Navigation)

Stack navigator, tab navigator, passing params, and navigation hooks
// npm install @react-navigation/native @react-navigation/native-stack
// npm install react-native-screens react-native-safe-area-context

import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";

type RootStackParamList = {
  Home:    undefined;
  Profile: { userId: string };
  Settings: undefined;
};

const Stack = createNativeStackNavigator<RootStackParamList>();
const Tab   = createBottomTabNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home"     component={HomeScreen} />
        <Stack.Screen name="Profile"  component={ProfileScreen}
          options={{ title: "User Profile", headerBackTitle: "Back" }} />
        <Stack.Screen name="Settings" component={SettingsScreen}
          options={{ presentation: "modal" }} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

// Navigate + pass params:
navigation.navigate("Profile", { userId: "alice" });
navigation.push("Profile", { userId: "bob" });  // add to stack (even if same screen)
navigation.goBack();
navigation.replace("Home");   // replace current screen

// Access params:
function ProfileScreen({ route, navigation }) {
  const { userId } = route.params;
}
// Or with hooks:
import { useNavigation, useRoute } from "@react-navigation/native";
const navigation = useNavigation();
const route      = useRoute<RouteProp<RootStackParamList, "Profile">>();

4. APIs — AsyncStorage, Permissions & Platform

AsyncStorage, camera/location permissions, Linking, Vibration, and Expo APIs
// AsyncStorage (npm install @react-native-async-storage/async-storage):
import AsyncStorage from "@react-native-async-storage/async-storage";

await AsyncStorage.setItem("user-token", JSON.stringify(token));
const raw = await AsyncStorage.getItem("user-token");
const token = raw ? JSON.parse(raw) : null;
await AsyncStorage.removeItem("user-token");
await AsyncStorage.clear();   // wipe all storage

// Permissions (Expo: expo-location, expo-camera, expo-notifications):
import * as Location from "expo-location";
import { Camera } from "expo-camera";

const { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") return;  // permission denied
const loc = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.High });
const { latitude, longitude } = loc.coords;

const [permission] = await Camera.requestCameraPermissionsAsync();

// Linking — open URLs, deep links:
import { Linking } from "react-native";
await Linking.openURL("https://example.com");
await Linking.openURL("mailto:support@example.com");
await Linking.openURL("tel:+15551234567");

// Vibration:
import { Vibration } from "react-native";
Vibration.vibrate(100);              // 100ms vibration
Vibration.vibrate([0, 100, 50, 100]); // pattern: wait, vibrate, wait, vibrate
Vibration.cancel();

// Keyboard:
import { Keyboard, KeyboardAvoidingView } from "react-native";
Keyboard.dismiss();
// Wrap form in KeyboardAvoidingView to avoid keyboard covering input:
<KeyboardAvoidingView behavior={Platform.OS === "ios" ? "padding" : "height"} style={{ flex: 1 }}>
  <TextInput ... />
</KeyboardAvoidingView>

5. Expo vs Bare RN, Performance & Testing

Expo workflow, performance tips (memo, FlatList), and testing with Jest + RNTL
// Expo (recommended for most projects):
npx create-expo-app@latest my-app --template default  // TypeScript + file-based routing
cd my-app
npx expo start     // run on device via Expo Go app, or simulator

// Expo Router — file-based navigation (like Next.js App Router):
// app/index.tsx          → /
// app/profile/[id].tsx   → /profile/:id
// app/(tabs)/home.tsx    → tab route

import { useLocalSearchParams, Link } from "expo-router";
const { id } = useLocalSearchParams();
<Link href="/profile/alice">View Profile</Link>

// Performance:
// 1. Use FlatList not .map() for long lists — virtualized rendering
// 2. memo() for expensive components:
const UserCard = React.memo(({ user }) => <View>...</View>);
// 3. useCallback for callbacks passed to memoized children
// 4. InteractionManager.runAfterInteractions for heavy work after animations
import { InteractionManager } from "react-native";
InteractionManager.runAfterInteractions(() => { heavyWork(); });
// 5. useMemo for expensive calculations
// 6. Avoid anonymous functions in render (creates new ref each render)

// Testing (React Native Testing Library):
// npm install -D @testing-library/react-native
import { render, screen, fireEvent } from "@testing-library/react-native";
it("renders greeting", () => {
  render(<Greeting name="Alice" />);
  expect(screen.getByText("Hello, Alice")).toBeTruthy();
  fireEvent.press(screen.getByText("Say hi"));
  expect(screen.getByText("Hi!")).toBeTruthy();
});

Track Node.js and React ecosystem releases at ReleaseRun. Related: React Reference | TypeScript Reference | Zustand Reference

🔍 Free tool: npm Package Health Checker — check react-native and its ecosystem packages for EOL status, known CVEs, and active maintenance.

Founded

2023 in London, UK

Contact

hello@releaserun.com