DS DevShelfHub Projects · AI tools
Cheatsheets / React Native
Cheatsheet · Dev tooling

React Native: Components, Navigation and New Architecture Reference Guide

By DevShelfHub

Core components, hooks, navigation, lists, gestures, animation, native modules, Expo vs bare, platform APIs — the cross-platform mobile surface day-to-day.

118 items 8 min Components Navigation Native

Start hereQuick start · 6 you’ll reach for daily

New appnpx create-expo-app@latest
Runnpx expo start
Layout<View style={ {flex:1} }>
Tappable<Pressable onPress={fn}>
List<FlatList data={…} renderItem />
Navigatenavigation.navigate('Detail')

Target versions · paceVersions

Targets: react-native ≥ 0.75 react ≥ 18.3 expo ≥ SDK 52 @react-navigation/native ≥ 7 node ≥ 20

The New Architecture (Fabric renderer + TurboModules + Hermes) is the default in RN 0.75+ and Expo SDK 52+. Old-arch is being phased out — most third-party libraries now ship interop shims, but a few still need patches. If a native library throws at install, check its README for a newArchEnabled flag. This sheet pins to May 2026; check reactnative.dev or docs.expo.dev for current versions.

Install · runSetup

bash
# Expo (managed) — fastest start, no Xcode/Android Studio needed
npx create-expo-app@latest MyApp --template
cd MyApp
npx expo start                  # press i (iOS) / a (Android) / w (web)

# Bare React Native (full native access)
npx @react-native-community/cli@latest init MyApp
cd MyApp
npx pod-install ios             # macOS only
npm run ios                     # or npm run android

# Node ≥ 20, watchman recommended on macOS:
brew install watchman
Expo vs bare: Expo’s managed workflow is the default recommendation — OTA updates, config plugins, no Xcode required for most apps. Drop to bare only when you need a native module Expo’s prebuilt runtime doesn’t support, or you’re wrapping an existing native app.

Where things liveCommon imports

Core primitives ship in react-native. Navigation, gestures, animation, storage, and most device APIs are separate packages — install on demand.

import { View, Text, Image, ScrollView } from 'react-native'Core layout + content primitives.
import { Pressable, TouchableOpacity, Button } from 'react-native'Tappable wrappers. Preferred Pressable.
import { TextInput, Switch, Slider } from 'react-native'Form primitives.
import { FlatList, SectionList } from 'react-native'Virtualized lists.
import { StyleSheet, useWindowDimensions, PixelRatio } from 'react-native'Style + responsive helpers.
import { Platform, StatusBar, Linking, Alert } from 'react-native'Platform branching + system APIs.
import { NavigationContainer } from '@react-navigation/native'Root navigation wrapper.
import { createNativeStackNavigator } from '@react-navigation/native-stack'Native stack (UIKit / Fragment).
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'Tabs.
import { SafeAreaView } from 'react-native-safe-area-context'Notch / dynamic-island insets.
import AsyncStorage from '@react-native-async-storage/async-storage'Key-value persistence.
import Animated from 'react-native-reanimated'UI-thread animations.
import { Gesture, GestureDetector } from 'react-native-gesture-handler'Pan / pinch / long-press.
import * as ImagePicker from 'expo-image-picker'Camera roll / capture (Expo).

Building blocksCore components

Layout & content

<View style={...}>The div. Default flex container.
<Text>hello</Text>All text must be wrapped. Plain strings outside <Text> throw.
<Image source={ {uri:'…'} } style={ {width,height} } />Remote image. Width+height required.
<Image source={require('./logo.png')} />Bundled asset. Resolution-suffixed (@2x, @3x) picked automatically.
<ScrollView contentContainerStyle={...}>Non-virtualized scroller. Avoid for long lists.
<SafeAreaView>Pads for notches/home-indicator. Use the one from safe-area-context.
<KeyboardAvoidingView behavior="padding">Lifts content above the keyboard.

Inputs & touch

<Pressable onPress={fn}>Preferred Modern touchable. Supports pressed state in style.
<TouchableOpacity onPress={fn}>Legacy Older API. Still works; Pressable is more flexible.
<Button title="ok" onPress={fn} />Platform-styled button. No style prop.
<TextInput value={v} onChangeText={setV} />Single-line input.
<TextInput multiline numberOfLines={4} />Multi-line.
<Switch value={on} onValueChange={setOn} />Native toggle.

Minimal component

javascript
import { View, Text, Pressable, StyleSheet } from 'react-native';
import { useState } from 'react';

export default function Counter() {
  const [n, setN] = useState(0);
  return (
    
      Count: {n}
       setN(n + 1)} style={styles.btn}>
        Increment
      
    
  );
}

const styles = StyleSheet.create({
  box:      { padding: 16, gap: 12 },
  label:    { fontSize: 18, fontWeight: '600' },
  btn:      { padding: 12, borderRadius: 8, backgroundColor: '#2563eb' },
  btnText:  { color: 'white', textAlign: 'center', fontWeight: '600' },
});

Flexbox · StyleSheetStyling & layout

StyleSheet

StyleSheet.create({ box: { padding: 16 } })Validated style objects. Pass via style={styles.box}.
style={[styles.base, isActive && styles.active]}Compose / conditional styles.
style={({ pressed }) => ({ opacity: pressed ? 0.6 : 1 })}Pressable state-style callback.
StyleSheet.hairlineWidth1px on web ≈ thinner on retina. Use for divider borders.
StyleSheet.absoluteFillShorthand for position:'absolute', top:0, left:0, ….

Flexbox — defaults differ from web

flexDirection: 'column'Default in RN (vs row on web).
flex: 1Fills the parent on the main axis.
justifyContentMain-axis alignment: flex-start | center | space-between | …
alignItemsCross-axis alignment.
gap: 12Space between children. RN 0.71+.
aspectRatio: 16 / 9Sets one axis from the other.

Responsive

const { width, height } = useWindowDimensions()Live-updating dimensions. Use this, not Dimensions.get.
PixelRatio.get()Device pixel ratio.
Platform.OS === 'ios'Branch by platform.
Platform.select({ ios: 'A', android: 'B' })Per-platform value.

React + RN-specificHooks & state

const [v, setV] = useState(initial)Local state. Same as web React.
useEffect(() => { … }, [deps])Side effects after commit.
useLayoutEffect(…)Synchronous post-mount. Use for header config in navigation.
useRef(null)Mutable ref; ref.current.
useMemo / useCallbackMemoize values / handlers. Watch out for stale closures.
useWindowDimensions()Reactive screen size.
useColorScheme()'light' | 'dark' | null. Live-updating.
useFocusEffect(useCallback(…, []))Runs when screen gains focus. From @react-navigation/native.
useIsFocused()Boolean, re-renders on focus change.

Virtualized scrollingLists

<FlatList data renderItem keyExtractor />Virtualized list. The default.
renderItem={({ item, index }) => …}Per-row render. Memoize for long lists.
keyExtractor={(it) => it.id}Stable key. Defaults to item.key or index.
onEndReached + onEndReachedThresholdInfinite scroll trigger.
refreshControl={<RefreshControl …/>}Pull-to-refresh.
ListHeaderComponent / ListFooterComponentSticky-able header/footer.
getItemLayout={(d,i) => ({length, offset, index})}Skip layout pass. Huge perf win for fixed-height rows.
<SectionList sections renderItem renderSectionHeader />Grouped list with headers.
FlashList from @shopify/flash-listPreferred Drop-in replacement; smoother for heavy rows.

FlatList with pull-to-refresh & infinite scroll

javascript
import { FlatList, Text, View, RefreshControl } from 'react-native';
import { useState, useCallback } from 'react';

export function Feed({ items, onRefresh, onEndReached }) {
  const [refreshing, setRefreshing] = useState(false);

  const handleRefresh = useCallback(async () => {
    setRefreshing(true);
    await onRefresh();
    setRefreshing(false);
  }, [onRefresh]);

  return (
     it.id}
      renderItem={({ item }) => (
        
          {item.title}
        
      )}
      ItemSeparatorComponent={() => }
      onEndReached={onEndReached}
      onEndReachedThreshold={0.5}
      refreshControl={}
      initialNumToRender={10}
    />
  );
}
<NavigationContainer>Root wrapper. Exactly one per app.
createNativeStackNavigator()Preferred Uses platform-native stack (faster, gestures).
createStackNavigator()JS-driven stack. Use only if you need custom transitions.
createBottomTabNavigator()Tab bar.
createDrawerNavigator()Side drawer.
navigation.navigate('Detail', { id })Push or focus existing screen.
navigation.push('Detail', { id })Always pushes a new instance.
navigation.goBack()Pop.
navigation.replace('Login')Swap current screen (auth flows).
navigation.setOptions({ title: 'New' })Update header dynamically.
route.paramsRead params passed in.
useNavigation() / useRoute()Hooks for any nested component.
Expo Router (file-based) is an alternative built on react-navigation: app/index.tsx, app/[id].tsx. Same primitives below; the routes are inferred from filesystem.

Stack + params

javascript
// npm i @react-navigation/native @react-navigation/native-stack
// npx expo install react-native-screens react-native-safe-area-context

import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator();

function Home({ navigation }) {
  return 

UI thread is the goalAnimation & gestures

Reanimated 3 Preferred

useSharedValue(0)Mutable value living on the UI thread.
useAnimatedStyle(() => ({…}))Derived style. Runs on UI thread.
withTiming(to, { duration })Tween between values.
withSpring(to, { damping, stiffness })Physics-based.
withRepeat(anim, count, reverse)Loop / yoyo.
runOnJS(fn)(args)Call a JS-thread function from a worklet.

Legacy Animated API Legacy

Animated.Value(0)JS-thread value. Slower than Reanimated.
Animated.timing(v, { toValue, useNativeDriver: true }).start()Tween. Always set useNativeDriver.

Gesture Handler

Gesture.Tap().onEnd(fn)Tap recognizer.
Gesture.Pan().onUpdate(e => { x.value = e.translationX })Drag.
Gesture.Pinch() / Gesture.Rotation()Multi-touch.
<GestureDetector gesture={g}>Wrap the view to receive the gesture.

Press-to-bounce

javascript
// npx expo install react-native-reanimated
import Animated, {
  useSharedValue, useAnimatedStyle, withSpring, withTiming,
} from 'react-native-reanimated';
import { Pressable, View } from 'react-native';

export function Bouncer() {
  const scale = useSharedValue(1);
  const style = useAnimatedStyle(() => ({ transform: [{ scale: scale.value }] }));

  return (
     { scale.value = withSpring(0.92); }}
      onPressOut={() => { scale.value = withSpring(1);    }}
    >
      
    
  );
}

// One-shot timing
// opacity.value = withTiming(1, { duration: 300 });

Fetch · storageNetworking & storage

fetch(url, { method, headers, body })Global fetch. Works the same as web.
await fetch(url).then(r => r.json())Read JSON body.
AbortController + signalCancel an in-flight request. Wire to useEffect cleanup.
AsyncStorage.setItem(key, value)Persistent key/value. Strings only.
AsyncStorage.getItem(key)Returns string | null.
AsyncStorage.multiGet([…])Batch read.
SecureStore.setItemAsync (expo-secure-store)Keychain / Keystore for tokens.
MMKV from react-native-mmkvPreferred Sync, ~30× faster than AsyncStorage for hot keys.
@tanstack/react-queryDe-facto data layer: caching, retries, refetch on focus.

Device featuresPlatform APIs

Alert.alert('Title', 'msg', [{text:'OK'}])Native dialog.
Linking.openURL('https://…')Open in browser / handler.
Linking.openSettings()Jump to app settings page.
Linking.addEventListener('url', fn)Handle deep links.
Clipboard.setStringAsync('…')From expo-clipboard.
Haptics.impactAsync(…)Vibration / haptics. expo-haptics.
ImagePicker.launchImageLibraryAsync(…)Camera roll. Requests permission inline.
Location.requestForegroundPermissionsAsync()Foreground GPS access.
Notifications.scheduleNotificationAsync(…)Local notifications.
Camera (react-native-vision-camera)Frame-processor camera. Beats Expo Camera for AI workloads.
SafeAreaProvider + useSafeAreaInsets()Pixel-perfect notch / dynamic-island offsets.

Bridge to platform codeNative modules

NativeModules.MyModule.doThing()Legacy Bridge-based call. Async, JSON-serialized.
TurboModuleRegistry.getEnforcing<Spec>('Name')Preferred JSI-based TurboModule. Sync-capable, typed.
NativeEventEmitterSubscribe to native events.
requireNativeComponent('MyView')Legacy Bridge-side native view.
codegenNativeComponent<Props>('MyView')Preferred Fabric native component via codegen.
expo-modules-coreAuthoring API for cross-platform native modules. Cleaner than raw bridge.
npx expo prebuildGenerate ios/ & android/ from app.json + config plugins.

Full app · ~45 linesEnd-to-end · List + Detail + Persist

Fetches a feed, navigates to a detail screen, persists a favourite to AsyncStorage. Drop into a fresh Expo app and run npx expo start.

javascript
// A minimal Expo app: fetch a list, navigate to detail, persist a favourite.
// Run with: npx expo start
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useEffect, useState } from 'react';
import { FlatList, Pressable, Text, View } from 'react-native';

const Stack = createNativeStackNavigator();

function List({ navigation }) {
  const [items, setItems] = useState([]);
  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
      .then((r) => r.json()).then(setItems);
  }, []);
  return (
     String(it.id)}
      renderItem={({ item }) => (
         navigation.navigate('Detail', { post: item })}>
          {item.title}
        
      )}
    />
  );
}

function Detail({ route }) {
  const { post } = route.params;
  const fav = async () => AsyncStorage.setItem(`fav:${post.id}`, '1');
  return (
    
      {post.title}
      {post.body}
      Save ★
    
  );
}

export default function App() {
  return (
    
      
        
        
      
    
  );
}

Inspect · shipDebugging & build

⌘D (iOS) / ⌘M (Android emulator)Dev menu: reload, perf monitor, element inspector.
console.log → terminalLogs stream to Metro/Expo CLI.
npx react-native log-ios / log-androidTail device logs (bare RN).
Flipper / RN DevToolsInspect network, layout, Redux. RN DevTools is the new default in 0.76+.
npx expo doctorDiagnoses dep mismatches, native config drift.
eas build --profile production --platform allExpo Application Services cloud build. Produces .ipa + .aab.
eas submit --platform iosUpload to App Store Connect / Play Console.
eas update --branch productionOTA JS bundle update. Native code requires a rebuild.

Best practiceGood to know

Reach for FlashList before FlatList grows. Once row content is dynamic-height or images, FlatList’s memory ballooning is the most common source of jank reports. @shopify/flash-list is a near drop-in.
Animations belong on the UI thread. Reanimated worklets, or the legacy Animated API with useNativeDriver: true. JS-driven animation drops to a 5fps slideshow as soon as the JS thread does any real work.
Use Pressable, not TouchableOpacity, in new code. Same touch handling, but the pressed state hook into style and built-in hitSlop/pressRetentionOffset replace a stack of older props.

Common trapsWatch out for

Plain strings outside <Text> throw. <View>hello</View> crashes. All text must be inside <Text> — including whitespace between siblings.
Default flexDirection is column, not row. Layouts copied from web land arranged top-to-bottom. Set flexDirection: 'row' explicitly.
Native library installs need a rebuild. Adding a package that touches native code (camera, MMKV, BLE) requires npx pod-install + rebuild — or eas build. A Metro reload is not enough; Expo Go won’t pick it up at all.

Go deeperSee also

React Native FAQ

What is React Native used for?

React Native lets you build iOS and Android mobile apps using React and JavaScript. The New Architecture (Fabric and TurboModules, default in 0.75+) renders native UI widgets, not a WebView, so performance is close to fully native apps. Expo provides a managed workflow for faster iteration.

What is Expo and is it required for React Native?

Expo is an open-source platform that wraps React Native with pre-built native modules, a managed build service (EAS), and the Expo Go app for instant preview. It is optional — bare React Native works without it — but Expo cuts setup time significantly for most projects.

What is the New Architecture in React Native?

The New Architecture consists of Fabric (a new rendering system), TurboModules (lazy-loaded native modules), and the Hermes JavaScript engine. It is the default in React Native 0.75+ and Expo SDK 52+. It enables synchronous native layout, concurrent React features, and faster startup.

How does navigation work in React Native?

React Navigation (@react-navigation/native) is the standard library for screen navigation. Stack, Tab, and Drawer navigators handle the three most common patterns. In Expo Router, the file-system defines routes — similar to Next.js — which is the recommended default for new Expo projects.

What is the difference between React Native and React?

React is a JavaScript library for web UIs that renders to HTML DOM elements. React Native uses the same component model and hooks but renders to native iOS and Android views (View, Text, Image, Pressable) instead of HTML. Sharing logic between web and mobile is possible via shared hooks and context.