# Code Reference — React Native

_75 pages_

---
# React Native (/docs/react-native)



# React Native [#react-native]

Mobile UI, APIs, Expo.

Browse the sidebar for every cheat sheet in this section.

## Sections [#sections]

* [Examples](./examples)
* [Expo](./expo)


---

# Accessibility (/docs/react-native/accesebility)



# Accessibility [#accessibility]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Make screens usable with VoiceOver / TalkBack via accessibility props on native views. Test with real screen readers; labels and roles matter more than visual-only cues.

## 🔧 Core concepts [#-core-concepts]

* **`accessible`** — groups children into one focusable element.
* **`accessibilityLabel` / `accessibilityHint`** — what is read aloud.
* **`accessibilityRole`** — `button`, `header`, `link`, `image`, `adjustable`, …
* **`accessibilityState`** — `\{ disabled, selected, checked, busy, expanded \}`.
* **`accessibilityActions` / `onAccessibilityAction`** — custom actions.

## 💡 Examples [#-examples]

```tsx
import { Pressable, Text } from "react-native";

export function IconButton({
  label,
  onPress,
}: {
  label: string;
  onPress: () => void;
}) {
  return (
    <Pressable
      onPress={onPress}
      accessibilityRole="button"
      accessibilityLabel={label}
      accessibilityHint="Double tap to activate"
    >
      <Text>★</Text>
    </Pressable>
  );
}
```

```tsx
<View
  accessible
  accessibilityRole="header"
  accessibilityLabel="Account settings"
>
  <Text>Settings</Text>
</View>
```

## ⚠️ Pitfalls [#️-pitfalls]

* Icon-only buttons without `accessibilityLabel`.
* Nesting multiple `accessible` views that trap focus incorrectly.
* Relying on placeholder text as the only label for inputs — set explicit labels.

## 🔗 Related [#-related]

* [touchable.md](/docs/react-native/touchable) — press targets
* [basic\_primitives.md](/docs/react-native/basic-primitives) — Text / View
* [gesture.md](/docs/react-native/gesture) — gestures vs a11y
* [Expo/plugins.md](/docs/react-native/expo/plugins) — native config


---

# Activity Indicator (/docs/react-native/activity-indicator)



# Activity Indicator [#activity-indicator]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`ActivityIndicator` shows a platform-native spinner for loading states. Prefer it for indeterminate progress; use progress bars for determinate tasks. Size and color are the main knobs.

## 🔧 Core concepts [#-core-concepts]

| Prop               | Role                                  |
| ------------------ | ------------------------------------- |
| `animating`        | Show/hide animation                   |
| `size`             | `small` / `large` (number on Android) |
| `color`            | Spinner color                         |
| `hidesWhenStopped` | iOS hide when not animating           |

Place near the content that is loading; announce loading to a11y when blocking.

## 💡 Examples [#-examples]

```tsx
import { ActivityIndicator, View, StyleSheet, Text } from "react-native";

export function LoadingBlock({ label = "Loading" }: { label?: string }) {
  return (
    <View
      style={styles.wrap}
      accessibilityRole="progressbar"
      accessibilityLabel={label}
    >
      <ActivityIndicator size="large" color="#111" />
      <Text style={styles.label}>{label}</Text>
    </View>
  );
}

export function InlineBusy({ busy }: { busy: boolean }) {
  return busy ? <ActivityIndicator /> : null;
}

const styles = StyleSheet.create({
  wrap: { alignItems: "center", justifyContent: "center", padding: 24, gap: 12 },
  label: { color: "#444" },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Full-screen spinner with no escape for slow networks.
* Wrong contrast (`color` on similar background).
* Leaving `animating` true forever after errors.
* Using indicators instead of skeleton UI for large layout shifts.

## 🔗 Related [#-related]

* [refresh\_control.md](/docs/react-native/refresh-control) — pull to refresh
* [modal.md](/docs/react-native/modal) — blocking overlays
* [networking.md](/docs/react-native/networking) — request states
* [accesebility.md](/docs/react-native/accesebility) — announcements
* [styling.md](/docs/react-native/styling) — layout


---

# Alert (/docs/react-native/alert)



# Alert [#alert]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`Alert.alert` shows a native system dialog with a title, message, and buttons. Use for confirmations and simple errors. For custom UI, use a modal—not Alert. On web/unsupported platforms behavior differs.

## 🔧 Core concepts [#-core-concepts]

| Piece               | Role                                 |
| ------------------- | ------------------------------------ |
| `title` / `message` | Copy                                 |
| `buttons`           | `\{ text, onPress, style \}[]`       |
| `style`             | `default` / `cancel` / `destructive` |
| `Alert.prompt`      | iOS text prompt only                 |

Buttons dismiss the alert when pressed; keep handlers light.

## 💡 Examples [#-examples]

```tsx
import { Alert, Pressable, Text } from "react-native";

export function DeleteButton({ onConfirm }: { onConfirm: () => void }) {
  return (
    <Pressable
      onPress={() =>
        Alert.alert("Delete item?", "This cannot be undone.", [
          { text: "Cancel", style: "cancel" },
          { text: "Delete", style: "destructive", onPress: onConfirm },
        ])
      }
    >
      <Text>Delete</Text>
    </Pressable>
  );
}

function showError(err: Error) {
  Alert.alert("Something went wrong", err.message);
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Relying on `Alert.prompt` on Android—not available.
* Stacking multiple alerts.
* Putting long forms inside Alert—use a screen/modal.
* Forgetting a cancel action on destructive flows.

## 🔗 Related [#-related]

* [modal.md](/docs/react-native/modal) — custom dialogs
* [pressable.md](/docs/react-native/pressable) — triggers
* [vibration.md](/docs/react-native/vibration) — haptic emphasis
* [accesebility.md](/docs/react-native/accesebility) — announcements
* [share.md](/docs/react-native/share) — system sheets


---

# Animation (/docs/react-native/animation)



# Animation [#animation]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Animate with the built-in `Animated` API, `LayoutAnimation`, or libraries like **Reanimated**. Prefer the UI thread (Reanimated / native driver) for smooth 60fps motion.

## 🔧 Core concepts [#-core-concepts]

* **`Animated.Value`** — drive opacity, transform, color interpolations.
* **`useNativeDriver: true`** — opacity/transform only; offloads to native.
* **`Animated.timing` / `spring` / `parallel` / `sequence`**.
* **Reanimated** — `useSharedValue`, `withTiming`, `useAnimatedStyle` for gestures + UI thread.
* **`LayoutAnimation`** — simple layout transitions (Android needs `UIManager` flag on older RN).

## 💡 Examples [#-examples]

```tsx
import { useRef, useEffect } from "react";
import { Animated, View } from "react-native";

export function FadeIn({ children }: { children: React.ReactNode }) {
  const opacity = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.timing(opacity, {
      toValue: 1,
      duration: 300,
      useNativeDriver: true,
    }).start();
  }, [opacity]);

  return <Animated.View style={{ opacity }}>{children}</Animated.View>;
}
```

```tsx
import Animated, { useSharedValue, withSpring, useAnimatedStyle } from "react-native-reanimated";

export function Bounce() {
  const scale = useSharedValue(1);
  const style = useAnimatedStyle(() => ({ transform: [{ scale: scale.value }] }));
  return (
    <Animated.View
      style={style}
      onTouchEnd={() => {
        scale.value = withSpring(1.2);
      }}
    />
  );
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* `useNativeDriver: true` with `width`/`height`/`top` — not supported; use Reanimated or layout anims.
* Starting animations every render without deps.
* Fighting the navigator’s own transition configs.

## 🔗 Related [#-related]

* [transition.md](/docs/react-native/transition) — screen transitions
* [gesture.md](/docs/react-native/gesture) — gesture-driven motion
* [layout.md](/docs/react-native/layout) — layout props
* [touchable.md](/docs/react-native/touchable) — press feedback


---

# AppRegistry (/docs/react-native/appregistry)



# AppRegistry [#appregistry]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`AppRegistry` is the JS entry that registers the root component. The native host looks up the app key and runs that component. Expo / CLI templates wire this for you.

## 🔧 Core concepts [#-core-concepts]

* **`AppRegistry.registerComponent(appKey, () => Root)`** — required entry.
* **App key** — must match native (`AppDelegate` / `MainActivity` / `app.json` name).
* **`runApplication`** — used by the native side; rarely called from app code.
* **Expo** — `registerRootComponent` from `expo` wraps `AppRegistry`.

## 💡 Examples [#-examples]

```tsx
import { AppRegistry } from "react-native";
import App from "./App";
import { name as appName } from "./app.json";

AppRegistry.registerComponent(appName, () => App);
```

```tsx
// Expo
import { registerRootComponent } from "expo";
import App from "./App";

registerRootComponent(App);
```

## ⚠️ Pitfalls [#️-pitfalls]

* Mismatched app name between JS and native → blank screen / redbox.
* Registering twice with different roots in the same bundle.
* Forgetting the factory `() => App` (passing `App` directly is also accepted in modern RN, but factory is the classic pattern).

## 🔗 Related [#-related]

* [basic\_primitives.md](/docs/react-native/basic-primitives) — building UI
* [Expo/filestructure.md](/docs/react-native/expo/filestructure) — Expo entry
* [Expo/config.md](/docs/react-native/expo/config) — app name / slug
* [widget.md](/docs/react-native/widget) — alternate surfaces


---

# AppState (/docs/react-native/appstate)



# AppState [#appstate]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`AppState` reports whether the app is `active`, `background`, or (iOS) `inactive`. Subscribe to changes to pause video, sync data, or lock a secure screen when backgrounding.

## 🔧 Core concepts [#-core-concepts]

| State        | Meaning                       |
| ------------ | ----------------------------- |
| `active`     | Foreground, interactive       |
| `background` | Not visible                   |
| `inactive`   | iOS transition / multitasking |

APIs: `AppState.currentState`, `addEventListener('change', handler)`.

## 💡 Examples [#-examples]

```tsx
import { useEffect, useRef, useState } from "react";
import { AppState, Text } from "react-native";

export function useAppActive() {
  const [active, setActive] = useState(AppState.currentState === "active");
  useEffect(() => {
    const sub = AppState.addEventListener("change", (next) => {
      setActive(next === "active");
    });
    return () => sub.remove();
  }, []);
  return active;
}

export function SecureGate({ children }: { children: React.ReactNode }) {
  const appState = useRef(AppState.currentState);
  const [locked, setLocked] = useState(false);

  useEffect(() => {
    const sub = AppState.addEventListener("change", (next) => {
      if (
        appState.current === "active" &&
        next.match(/inactive|background/)
      ) {
        setLocked(true);
      }
      appState.current = next;
    });
    return () => sub.remove();
  }, []);

  if (locked) return <Text>Unlock to continue</Text>;
  return <>{children}</>;
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Doing heavy work on every blur without debounce.
* Forgetting to remove the subscription.
* Assuming `inactive` exists on Android the same way.
* Polling instead of listening.

## 🔗 Related [#-related]

* [biometrics.md](/docs/react-native/biometrics) — unlock
* [player.md](/docs/react-native/player) — pause media
* [notification.md](/docs/react-native/notification) — background
* [storage.md](/docs/react-native/storage) — persist on blur
* [navigation.md](/docs/react-native/navigation) — blur events


---

# BackHandler (/docs/react-native/backhandler)



# BackHandler [#backhandler]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`BackHandler` listens for the Android hardware back button (and some back gestures). iOS has no system back button — use navigation stack gestures instead.

## 🔧 Core concepts [#-core-concepts]

* **`BackHandler.addEventListener("hardwareBackPress", handler)`**.
* **Return `true`*&#x2A; — you handled it; &#x2A;*`false`** — let default (exit / pop) proceed.
* **Cleanup** — remove the subscription in effect cleanup.
* **React Navigation** — prefer `beforeRemove` / stack options over raw BackHandler when using a navigator.

## 💡 Examples [#-examples]

```tsx
import { useEffect } from "react";
import { BackHandler, Alert } from "react-native";

export function useConfirmExit(enabled: boolean) {
  useEffect(() => {
    if (!enabled) return;
    const sub = BackHandler.addEventListener("hardwareBackPress", () => {
      Alert.alert("Exit?", "Leave the screen?", [
        { text: "Cancel", style: "cancel" },
        { text: "Exit", onPress: () => BackHandler.exitApp() },
      ]);
      return true;
    });
    return () => sub.remove();
  }, [enabled]);
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Stacking multiple listeners without cleanup → unpredictable back behavior.
* Handling back on iOS unnecessarily — no-op or wrong UX.
* Calling `exitApp()` casually — poor UX; prefer navigating away.

## 🔗 Related [#-related]

* [deeplinking.md](/docs/react-native/deeplinking) — navigation entry
* [drawer.md](/docs/react-native/drawer) — drawer back behavior
* [modal.md](/docs/react-native/modal) — dismiss on back
* [gesture.md](/docs/react-native/gesture) — gesture navigation


---

# Basic primitives (/docs/react-native/basic-primitives)



# Basic primitives [#basic-primitives]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Core building blocks: `View`, `Text`, `Image`, `ScrollView`, `TextInput`, `Pressable`, `FlatList`. There is no HTML — style with the `StyleSheet` API (Flexbox by default).

## 🔧 Core concepts [#-core-concepts]

* **`View`** — container (like `div`); flex layout.
* **`Text`** — all strings must be inside `Text`.
* **`Image` / `ImageBackground`** — local `require` or remote `\{ uri \}`.
* **`ScrollView` vs `FlatList`** — lists of unknown length → `FlatList` / `SectionList`.
* **`StyleSheet.create`** — validated style objects; density-independent units.

## 💡 Examples [#-examples]

```tsx
import {
  View,
  Text,
  Image,
  StyleSheet,
  FlatList,
  Pressable,
} from "react-native";

const styles = StyleSheet.create({
  row: { flexDirection: "row", alignItems: "center", gap: 12, padding: 16 },
  title: { fontSize: 18, fontWeight: "600" },
  avatar: { width: 40, height: 40, borderRadius: 20 },
});

export function UserRow({
  name,
  uri,
  onPress,
}: {
  name: string;
  uri: string;
  onPress: () => void;
}) {
  return (
    <Pressable onPress={onPress} style={styles.row}>
      <Image source={{ uri }} style={styles.avatar} />
      <Text style={styles.title}>{name}</Text>
    </Pressable>
  );
}
```

```tsx
<FlatList
  data={users}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <UserRow {...item} onPress={() => {}} />}
/>
```

## ⚠️ Pitfalls [#️-pitfalls]

* Raw text outside `<Text>` crashes.
* Nesting `VirtualizedList` inside `ScrollView` without care → warnings / perf issues.
* Inline styles everywhere — harder to reuse; prefer `StyleSheet`.

## 🔗 Related [#-related]

* [layout.md](/docs/react-native/layout) — flex layout
* [touchable.md](/docs/react-native/touchable) — press handling
* [accesebility.md](/docs/react-native/accesebility) — a11y props
* [animation.md](/docs/react-native/animation) — animated views


---

# Biometrics (/docs/react-native/biometrics)



# Biometrics [#biometrics]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Biometric auth (Face ID, Touch ID, fingerprint) unlocks local secrets or confirms sensitive actions. Expo: &#x2A;*`expo-local-authentication`**. Bare: `react-native-biometrics` / Keychain integration. Always provide a device passcode fallback.

## 🔧 Core concepts [#-core-concepts]

| API                                 | Role                                           |
| ----------------------------------- | ---------------------------------------------- |
| `hasHardwareAsync`                  | Sensor present                                 |
| `isEnrolledAsync`                   | User enrolled biometrics                       |
| `supportedAuthenticationTypesAsync` | Face / fingerprint                             |
| `authenticateAsync`                 | Prompt                                         |
| Secure storage                      | Store tokens in Keychain/Keystore after unlock |

OS policy controls rate limits and lockouts.

## 💡 Examples [#-examples]

```tsx
import * as LocalAuthentication from "expo-local-authentication";
import { Alert, Pressable, Text } from "react-native";

export function UnlockButton({ onUnlocked }: { onUnlocked: () => void }) {
  return (
    <Pressable
      onPress={async () => {
        const hasHardware = await LocalAuthentication.hasHardwareAsync();
        const enrolled = await LocalAuthentication.isEnrolledAsync();
        if (!hasHardware || !enrolled) {
          Alert.alert("Biometrics unavailable", "Use your passcode instead.");
          return;
        }
        const result = await LocalAuthentication.authenticateAsync({
          promptMessage: "Unlock",
          fallbackLabel: "Use passcode",
          disableDeviceFallback: false,
        });
        if (result.success) onUnlocked();
      }}
    >
      <Text>Unlock with biometrics</Text>
    </Pressable>
  );
}
```

**Info.plist / Android:** Face ID usage string; no special permission for basic LocalAuthentication on modern Expo.

## ⚠️ Pitfalls [#️-pitfalls]

* Treating biometrics as server authentication—it's local presence only.
* Storing session tokens in AsyncStorage instead of secure storage.
* No fallback when enrollment is missing.
* Re-prompting in a tight loop after cancel.

## 🔗 Related [#-related]

* [Expo secure\_store](/docs/react-native/expo/secure-store) — Keychain
* [appstate.md](/docs/react-native/appstate) — lock on background
* [storage.md](/docs/react-native/storage) — insecure vs secure
* [permissions.md](/docs/react-native/permissions) — related prompts
* [alert.md](/docs/react-native/alert) — fallback UX


---

# Blur (/docs/react-native/blur)



# Blur [#blur]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Blurred glass effects use platform views: Expo `@react-native-community/blur&#x60; alternatives or &#x2A;*`expo-blur`** (`BlurView`). Common for headers, tab bars, and modal scrims. Performance varies—avoid huge animated blurs on low-end Android.

## 🔧 Core concepts [#-core-concepts]

| Piece       | Role                                     |
| ----------- | ---------------------------------------- |
| `BlurView`  | Blurs content behind the view            |
| `intensity` | Blur strength (Expo)                     |
| `tint`      | light / dark / default                   |
| Fallback    | Solid translucent color when unsupported |

Blur only affects views **behind** it in the native hierarchy—not React siblings painted later without proper ordering.

## 💡 Examples [#-examples]

```tsx
import { BlurView } from "expo-blur";
import { StyleSheet, Text, View } from "react-native";

export function FrostedHeader({ title }: { title: string }) {
  return (
    <View style={styles.wrap}>
      <BlurView intensity={60} tint="light" style={StyleSheet.absoluteFill} />
      <Text style={styles.title}>{title}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  wrap: {
    height: 56,
    justifyContent: "center",
    paddingHorizontal: 16,
    overflow: "hidden",
  },
  title: { fontSize: 17, fontWeight: "600" },
});
```

**Config plugin (Expo):** ensure `expo-blur` is installed; prebuild if needed.

## ⚠️ Pitfalls [#️-pitfalls]

* Expecting BlurView to blur its own children—it blurs what’s behind.
* Heavy blur + frequent re-renders → jank on Android.
* Missing fallback UI on web/unsupported targets.
* Stacking multiple full-screen blurs.

## 🔗 Related [#-related]

* [styling.md](/docs/react-native/styling) — translucent UI
* [modal.md](/docs/react-native/modal) — overlays
* [navigation.md](/docs/react-native/navigation) — translucent headers
* [Expo config](/docs/react-native/expo/config) — plugins
* [animation.md](/docs/react-native/animation) — animated opacity


---

# Camera (/docs/react-native/camera)



# Camera [#camera]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Camera access uses &#x2A;*`expo-camera`** (Expo) or `react-native-vision-camera` (bare/advanced). Request permission before preview; handle denied states. For still photos only, `expo-image-picker` may be enough.

## 🔧 Core concepts [#-core-concepts]

| Topic      | Notes                                |
| ---------- | ------------------------------------ |
| Permission | Camera (and mic for video)           |
| Preview    | `<CameraView>` / VisionCamera        |
| Capture    | `takePictureAsync` / photo callbacks |
| Facing     | front / back                         |
| Barcode    | Optional scanners                    |

Background: pause camera when screen blurs (`useIsFocused`).

## 💡 Examples [#-examples]

```tsx
import { useState, useRef, useEffect } from "react";
import { View, Pressable, Text, StyleSheet } from "react-native";
import { CameraView, useCameraPermissions } from "expo-camera";

export function CameraScreen() {
  const [permission, requestPermission] = useCameraPermissions();
  const ref = useRef<CameraView>(null);
  const [facing, setFacing] = useState<"back" | "front">("back");

  if (!permission) return <View />;
  if (!permission.granted) {
    return (
      <Pressable onPress={requestPermission}>
        <Text>Grant camera access</Text>
      </Pressable>
    );
  }

  return (
    <View style={styles.flex}>
      <CameraView ref={ref} style={styles.flex} facing={facing} />
      <Pressable
        style={styles.btn}
        onPress={async () => {
          const photo = await ref.current?.takePictureAsync();
          console.log(photo?.uri);
        }}
      >
        <Text>Capture</Text>
      </Pressable>
      <Pressable
        onPress={() => setFacing((f) => (f === "back" ? "front" : "back"))}
      >
        <Text>Flip</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  flex: { flex: 1 },
  btn: { padding: 16, backgroundColor: "#fff" },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Starting camera without permission UX.
* Leaving camera running on blurred tabs—battery/heat.
* Ignoring simulator limitations (no camera).
* Storing captures without compression / cleanup.

## 🔗 Related [#-related]

* [permissions.md](/docs/react-native/permissions) — runtime perms
* [Expo image\_picker](/docs/react-native/expo/image-picker) — gallery/camera stills
* [image.md](/docs/react-native/image) — display
* [navigation.md](/docs/react-native/navigation) — focus cleanup
* [appstate.md](/docs/react-native/appstate) — background


---

# Clipboard (/docs/react-native/clipboard)



# Clipboard [#clipboard]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Read and write the system clipboard. In modern RN / Expo, use `@react-native-clipboard/clipboard` or `expo-clipboard` — the core `Clipboard` API was removed from the RN core package.

## 🔧 Core concepts [#-core-concepts]

* **`setString(text)`** — copy to clipboard.
* **`getString()`** — async read (may need permission prompts on some platforms).
* **Expo** — `import * as Clipboard from "expo-clipboard"`.
* **Security** — don’t log clipboard contents; treat as sensitive.

## 💡 Examples [#-examples]

```tsx
import * as Clipboard from "expo-clipboard";
import { Pressable, Text, Alert } from "react-native";

export function CopyButton({ value }: { value: string }) {
  async function copy() {
    await Clipboard.setStringAsync(value);
    Alert.alert("Copied");
  }
  return (
    <Pressable onPress={copy} accessibilityRole="button" accessibilityLabel="Copy">
      <Text>Copy</Text>
    </Pressable>
  );
}
```

```tsx
import Clipboard from "@react-native-clipboard/clipboard";

async function paste() {
  const text = await Clipboard.getString();
  return text;
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Using deprecated `react-native` Clipboard import.
* Expecting sync `getString` — it’s async.
* Copying secrets into clipboard without user intent.

## 🔗 Related [#-related]

* [share.md](/docs/react-native/share) — system share sheet
* [storage.md](/docs/react-native/storage) — persistent storage
* [permissions.md](/docs/react-native/permissions) — platform permissions
* [Expo/plugins.md](/docs/react-native/expo/plugins) — Expo modules


---

# Deep linking (/docs/react-native/deep-linking)



# Deep linking [#deep-linking]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Deep links open a specific screen from a URL (`myapp://profile/42` or `https://…`). Use React Navigation linking config or Expo Router path maps.

## 🔧 Core concepts [#-core-concepts]

| Piece             | Role                                        |
| ----------------- | ------------------------------------------- |
| Scheme            | Custom URL scheme / universal links         |
| Linking API       | `Linking.getInitialURL`, `addEventListener` |
| Navigation config | Map path prefixes → screens                 |
| Expo Router       | File-based routes = URLs                    |

## 💡 Examples [#-examples]

```tsx
import * as Linking from 'expo-linking';

const url = Linking.createURL('profile/42');
// e.g. myapp://profile/42
```

```tsx
import { Linking } from 'react-native';

Linking.addEventListener('url', ({ url }) => {
  // navigate from url
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Test cold start (`getInitialURL`) and warm start (event) separately.
* Universal links need platform domain association files.
* Encode path params consistently.

## 🔗 Related [#-related]

* [launcher\_shortcut\_menu](/docs/react-native/launcher-shortcut-menu)
* [notifications](/docs/react-native/notifications)
* [getting\_started](/docs/react-native/getting-started)


---

# Deep linking (/docs/react-native/deeplinking)



# Deep linking [#deep-linking]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Deep links open a specific screen from a URL (`myapp://path`, HTTPS universal / app links). Configure native intent filters / associated domains, then map URLs in your navigator.

## 🔧 Core concepts [#-core-concepts]

* **Schemes** — custom (`myapp://`) vs HTTPS app links / universal links.
* **React Navigation** — `linking` config: `prefixes` + `config.screens`.
* **Expo** — `scheme` in `app.json` / `app.config`; `expo-linking`, `npx uri-scheme`.
* **Cold start** — read initial URL; also subscribe to URL events while running.

## 💡 Examples [#-examples]

```tsx
import { NavigationContainer } from "@react-navigation/native";

const linking = {
  prefixes: ["myapp://", "https://myapp.example.com"],
  config: {
    screens: {
      Home: "home",
      User: "users/:id",
    },
  },
};

export function RootNav() {
  return (
    <NavigationContainer linking={linking}>
      {/* navigators */}
    </NavigationContainer>
  );
}
```

```tsx
import * as Linking from "expo-linking";

const url = Linking.createURL("users/42");
// e.g. myapp://users/42
```

## ⚠️ Pitfalls [#️-pitfalls]

* Native config missing → links open browser or do nothing.
* Mismatched path params vs screen names.
* Not handling the case when the app is already open (`url` event).

## 🔗 Related [#-related]

* [Expo/config.md](/docs/react-native/expo/config) — scheme config
* [backhandler.md](/docs/react-native/backhandler) — Android back
* [notification.md](/docs/react-native/notification) — notification deep links
* [request.md](/docs/react-native/request) — API after open


---

# Dimensions (/docs/react-native/dimensions)



# Dimensions [#dimensions]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`Dimensions` and `useWindowDimensions` report screen/window size for responsive layouts. Prefer the hook so rotations and split-screen updates re-render.

## 🔧 Core concepts [#-core-concepts]

* **`useWindowDimensions()`** — `\{ width, height, scale, fontScale \}` (recommended).
* **`Dimensions.get("window" | "screen")`** — snapshot; subscribe manually if needed.
* **Safe areas** — use `react-native-safe-area-context`, not raw status bar math alone.
* **PixelRatio** — `PixelRatio.roundToNearestPixel`, font scaling awareness.

## 💡 Examples [#-examples]

```tsx
import { useWindowDimensions, View, Text } from "react-native";

export function Responsive() {
  const { width } = useWindowDimensions();
  const columns = width >= 768 ? 2 : 1;
  return (
    <View style={{ flexDirection: columns === 2 ? "row" : "column" }}>
      <Text>Columns: {columns}</Text>
    </View>
  );
}
```

```tsx
import { Dimensions } from "react-native";

const { width } = Dimensions.get("window");
```

## ⚠️ Pitfalls [#️-pitfalls]

* Caching `Dimensions.get` at module load — stale after rotate.
* Ignoring `fontScale` → clipped text for a11y users.
* Using screen size instead of window on Android with system bars / foldables.

## 🔗 Related [#-related]

* [layout.md](/docs/react-native/layout) — flex layouts
* [statusbar.md](/docs/react-native/statusbar) — insets / bars
* [platform\_specific.md](/docs/react-native/platform-specific) — platform splits
* [basic\_primitives.md](/docs/react-native/basic-primitives) — View sizing


---

# Drawer (/docs/react-native/drawer)



# Drawer [#drawer]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Drawers are side navigation panels. Use `@react-navigation/drawer` (or a custom `Animated`/`Reanimated` panel). Gesture + back-button behavior should match platform norms.

## 🔧 Core concepts [#-core-concepts]

* **Drawer navigator** — screens as drawer destinations; `drawerContent` for custom UI.
* **Options** — `drawerPosition`, `swipeEnabled`, `headerShown`.
* **Nesting** — often wrap a stack inside each drawer screen.
* **Custom** — modal-like overlay with translateX animation if you don’t need a full navigator.

## 💡 Examples [#-examples]

```tsx
import { createDrawerNavigator } from "@react-navigation/drawer";

const Drawer = createDrawerNavigator();

export function AppDrawer() {
  return (
    <Drawer.Navigator initialRouteName="Home">
      <Drawer.Screen name="Home" component={HomeScreen} />
      <Drawer.Screen name="Settings" component={SettingsScreen} />
    </Drawer.Navigator>
  );
}
```

```tsx
<Drawer.Navigator
  screenOptions={{
    drawerType: "front",
    swipeEdgeWidth: 40,
  }}
  drawerContent={(props) => <CustomDrawer {...props} />}
/>
```

## ⚠️ Pitfalls [#️-pitfalls]

* Conflicting gestures with tabs/stacks — tune `swipeEnabled` per screen.
* Forgetting Android back should close an open drawer first.
* Heavy drawer content re-rendering on every navigation event.

## 🔗 Related [#-related]

* [gesture.md](/docs/react-native/gesture) — swipe gestures
* [backhandler.md](/docs/react-native/backhandler) — Android back
* [transition.md](/docs/react-native/transition) — motion
* [layout.md](/docs/react-native/layout) — screen layout


---

# Examples (/docs/react-native/examples)



# Examples [#examples]

React Native notes in **Examples**.


---

# Dark Mode Toggle (/docs/react-native/examples/dark-mode-toggle)



# Dark Mode Toggle [#dark-mode-toggle]

*React Native · Example / how-to*

***

## 📋 Overview [#-overview]

Toggle light/dark appearance with React context and `useColorScheme`, applying colors through a small theme object.

## 🔧 Core concepts [#-core-concepts]

| Piece            | Role                     |
| ---------------- | ------------------------ |
| `useColorScheme` | System preference        |
| Context          | Share resolved theme     |
| Manual override  | User toggle beats system |
| Style tokens     | Background / text colors |

## 💡 Examples [#-examples]

**dark\_mode\_toggle.tsx:**

```tsx
import {
  createContext,
  useContext,
  useMemo,
  useState,
  type ReactNode,
} from "react";
import {
  Button,
  Text,
  useColorScheme,
  View,
  StyleSheet,
} from "react-native";

type Mode = "system" | "light" | "dark";
type Palette = { bg: string; fg: string };

const palettes: Record<"light" | "dark", Palette> = {
  light: { bg: "#ffffff", fg: "#111111" },
  dark: { bg: "#111111", fg: "#f5f5f5" },
};

type ThemeCtx = {
  mode: Mode;
  setMode: (m: Mode) => void;
  colors: Palette;
};

const ThemeContext = createContext<ThemeCtx | null>(null);

export function ThemeProvider({ children }: { children: ReactNode }) {
  const system = useColorScheme();
  const [mode, setMode] = useState<Mode>("system");
  const resolved = mode === "system" ? (system === "dark" ? "dark" : "light") : mode;
  const value = useMemo(
    () => ({ mode, setMode, colors: palettes[resolved] }),
    [mode, resolved],
  );
  return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
}

export function useTheme() {
  const ctx = useContext(ThemeContext);
  if (!ctx) throw new Error("useTheme requires ThemeProvider");
  return ctx;
}

export function DarkModeToggle() {
  const { mode, setMode, colors } = useTheme();
  return (
    <View style={[styles.box, { backgroundColor: colors.bg }]}>
      <Text style={{ color: colors.fg }}>Mode: {mode}</Text>
      <Button title="System" onPress={() => setMode("system")} />
      <Button title="Light" onPress={() => setMode("light")} />
      <Button title="Dark" onPress={() => setMode("dark")} />
    </View>
  );
}

const styles = StyleSheet.create({
  box: { flex: 1, gap: 8, padding: 16, justifyContent: "center" },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* System scheme can be `null` — default to light.
* Hard-coded `#fff` in child components ignores the theme — pass `colors` or use context.
* Persist `mode` if you want the choice to survive restarts.

## 🔗 Related [#-related]

* [FlatList search](/docs/react-native/examples/flatlist-search)
* [Form keyboard](/docs/react-native/examples/form-keyboard)


---

# FlatList Search (/docs/react-native/examples/flatlist-search)



# FlatList Search [#flatlist-search]

*React Native · Example / how-to*

***

## 📋 Overview [#-overview]

Filter a `FlatList` from a search `TextInput` with memoized data and stable `keyExtractor`.

## 🔧 Core concepts [#-core-concepts]

| Piece          | Role                              |
| -------------- | --------------------------------- |
| `FlatList`     | Virtualized list                  |
| `TextInput`    | Query string                      |
| `useMemo`      | Filter without extra renders cost |
| `keyExtractor` | Stable row ids                    |

## 💡 Examples [#-examples]

**FlatListSearch.tsx:**

```tsx
import { useMemo, useState } from "react";
import { FlatList, StyleSheet, Text, TextInput, View } from "react-native";

type Item = { id: string; title: string };

const DATA: Item[] = [
  { id: "1", title: "Alpha" },
  { id: "2", title: "Beta" },
  { id: "3", title: "Gamma" },
  { id: "4", title: "Delta" },
];

export function FlatListSearch() {
  const [query, setQuery] = useState("");

  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    if (!q) return DATA;
    return DATA.filter((item) => item.title.toLowerCase().includes(q));
  }, [query]);

  return (
    <View style={styles.container}>
      <TextInput
        value={query}
        onChangeText={setQuery}
        placeholder="Search…"
        autoCorrect={false}
        clearButtonMode="while-editing"
        style={styles.input}
      />
      <FlatList
        data={filtered}
        keyExtractor={(item) => item.id}
        keyboardShouldPersistTaps="handled"
        ListEmptyComponent={<Text>No matches</Text>}
        renderItem={({ item }) => (
          <Text style={styles.row}>{item.title}</Text>
        )}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 16 },
  input: {
    borderWidth: 1,
    borderColor: "#ccc",
    borderRadius: 8,
    paddingHorizontal: 12,
    paddingVertical: 8,
    marginBottom: 12,
  },
  row: { paddingVertical: 12, fontSize: 16 },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Inline `renderItem` recreates each render — extract a memoized row if profiling shows cost.
* Without `keyboardShouldPersistTaps`, taps on rows may dismiss the keyboard first.
* For remote search, debounce the query before fetching.

## 🔗 Related [#-related]

* [Form keyboard](/docs/react-native/examples/form-keyboard)
* [Dark mode toggle](/docs/react-native/examples/dark-mode-toggle)


---

# Form Keyboard (/docs/react-native/examples/form-keyboard)



# Form Keyboard [#form-keyboard]

*React Native · Example / how-to*

***

## 📋 Overview [#-overview]

Build a login-style form that scrolls with the keyboard using `KeyboardAvoidingView` and proper `TextInput` props.

## 🔧 Core concepts [#-core-concepts]

| Piece                            | Role                               |
| -------------------------------- | ---------------------------------- |
| `KeyboardAvoidingView`           | Shift UI above keyboard            |
| `behavior`                       | `padding` (iOS) vs platform quirks |
| `returnKeyType` / `blurOnSubmit` | Field-to-field flow                |
| `ScrollView`                     | Allow scroll when keyboard open    |

## 💡 Examples [#-examples]

**FormKeyboard.tsx:**

```tsx
import { useRef, useState } from "react";
import {
  KeyboardAvoidingView,
  Platform,
  ScrollView,
  StyleSheet,
  TextInput,
  Button,
  View,
} from "react-native";

export function FormKeyboard({ onSubmit }: { onSubmit: (email: string, password: string) => void }) {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const passwordRef = useRef<TextInput>(null);

  return (
    <KeyboardAvoidingView
      style={styles.flex}
      behavior={Platform.OS === "ios" ? "padding" : undefined}
      keyboardVerticalOffset={Platform.OS === "ios" ? 64 : 0}
    >
      <ScrollView
        contentContainerStyle={styles.content}
        keyboardShouldPersistTaps="handled"
      >
        <TextInput
          value={email}
          onChangeText={setEmail}
          placeholder="Email"
          autoCapitalize="none"
          keyboardType="email-address"
          textContentType="emailAddress"
          returnKeyType="next"
          onSubmitEditing={() => passwordRef.current?.focus()}
          style={styles.input}
        />
        <TextInput
          ref={passwordRef}
          value={password}
          onChangeText={setPassword}
          placeholder="Password"
          secureTextEntry
          textContentType="password"
          returnKeyType="done"
          onSubmitEditing={() => onSubmit(email.trim(), password)}
          style={styles.input}
        />
        <View style={styles.button}>
          <Button title="Sign in" onPress={() => onSubmit(email.trim(), password)} />
        </View>
      </ScrollView>
    </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  flex: { flex: 1 },
  content: { padding: 16, justifyContent: "center", flexGrow: 1 },
  input: {
    borderWidth: 1,
    borderColor: "#ccc",
    borderRadius: 8,
    padding: 12,
    marginBottom: 12,
  },
  button: { marginTop: 8 },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Android often needs `android:windowSoftInputMode` in the manifest / Expo app config.
* Nesting multiple scroll views fights the keyboard — keep one scroll parent.
* `keyboardVerticalOffset` must account for headers / safe area.

## 🔗 Related [#-related]

* [FlatList search](/docs/react-native/examples/flatlist-search)
* [Dark mode toggle](/docs/react-native/examples/dark-mode-toggle)


---

# Expo (/docs/react-native/expo)



# Expo [#expo]

React Native notes in **Expo**.


---

# Build (/docs/react-native/expo/build)



# Build [#build]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

**EAS Build** compiles iOS/Android binaries in the cloud (or locally) from your Expo project. Profiles in `eas.json` define development, preview, and production builds.

## 🔧 Core concepts [#-core-concepts]

* **Profiles** — `development` (dev client), `preview` (internal), `production` (store).
* **Workflow** — `eas build -p android|ios --profile <name>`.
* **Credentials** — EAS can manage keystores / distribution certs / provisioning.
* **App config** — `app.json` / `app.config.ts` + native projects via **CNG / prebuild**.
* **Local** — `eas build --local` when you need on-machine compiles.

## 💡 Examples [#-examples]

```json
// eas.json
{
  "cli": { "version": ">= 12.0.0" },
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal"
    },
    "preview": {
      "distribution": "internal",
      "android": { "buildType": "apk" }
    },
    "production": {
      "autoIncrement": true
    }
  },
  "submit": {
    "production": {}
  }
}
```

```shellscript
npx eas-cli login
npx eas-cli build --platform android --profile preview
npx eas-cli build --platform ios --profile production
npx eas-cli submit --platform ios --latest
```

## ⚠️ Pitfalls [#️-pitfalls]

* Building production without matching bundle ID / package + store listings.
* Forgetting `developmentClient: true` when you need custom native modules in dev.
* Native changes without rebuilding the binary (JS OTA can’t add native code).

## 🔗 Related [#-related]

* [commands.md](/docs/react-native/expo/commands) — CLI commands
* [config.md](/docs/react-native/expo/config) — app config
* [keystore\_sign.md](/docs/react-native/expo/keystore-sign) — Android signing
* [plugins.md](/docs/react-native/expo/plugins) — config plugins in builds


---

# Commands (/docs/react-native/expo/commands)



# Commands [#commands]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Day-to-day Expo CLI / EAS commands for local dev, prebuild, installs, and cloud builds. Prefer `npx expo` / `npx eas-cli` for pinned versions.

## 🔧 Core concepts [#-core-concepts]

* **Dev server** — `npx expo start` (tunnel / LAN / USB).
* **Platform run** — `npx expo run:android` / `run:ios` (dev client / bare).
* **Install** — `npx expo install <pkg>` aligns SDK-compatible versions.
* **Prebuild** — `npx expo prebuild` generates `ios/` / `android/`.
* **EAS** — `eas build`, `eas submit`, `eas update`, `eas credentials`.

## 💡 Examples [#-examples]

```shellscript
# Create & run
npx create-expo-app@latest MyApp
cd MyApp
npx expo start
npx expo start --tunnel

# Dependency aligned to SDK
npx expo install react-native-reanimated expo-secure-store

# Native projects + local run
npx expo prebuild
npx expo run:android
npx expo run:ios

# EAS
npx eas-cli build -p all --profile preview
npx eas-cli update --branch production --message "Fix crash"
npx eas-cli credentials
```

```shellscript
# Doctor / info
npx expo-doctor
npx expo config --type public
```

## ⚠️ Pitfalls [#️-pitfalls]

* `npm install` of Expo modules without `expo install` → version mismatches.
* Editing native folders then running prebuild without a strategy → overwrites (use plugins / CNG).
* Confusing Expo Go limits with what a **dev client** build can do.

## 🔗 Related [#-related]

* [build.md](/docs/react-native/expo/build) — EAS Build
* [config.md](/docs/react-native/expo/config) — configuration
* [filestructure.md](/docs/react-native/expo/filestructure) — project layout
* [plugins.md](/docs/react-native/expo/plugins) — native config


---

# Config (/docs/react-native/expo/config)



# Config [#config]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

App identity and native behavior live in &#x2A;*`app.json`*&#x2A; or dynamic &#x2A;*`app.config.js/ts`**. Config plugins mutate native projects at prebuild time. Use `extra` / `EXPO_PUBLIC_*` for non-secret runtime config.

## 🔧 Core concepts [#-core-concepts]

* **Identity** — `name`, `slug`, `version`, `orientation`, `icon`, `splash`.
* **Platform blocks** — `ios.bundleIdentifier`, `android.package`, permissions, intents.
* **Scheme** — deep linking `scheme`.
* **Plugins** — `plugins: ["expo-secure-store", [...]]`.
* **EAS** — `extra.eas.projectId`; env in EAS secrets / `.env`.

## 💡 Examples [#-examples]

```ts
// app.config.ts
import type { ExpoConfig } from "expo/config";

const config: ExpoConfig = {
  name: "MyApp",
  slug: "my-app",
  version: "1.0.0",
  scheme: "myapp",
  orientation: "portrait",
  icon: "./assets/icon.png",
  userInterfaceStyle: "automatic",
  splash: {
    image: "./assets/splash.png",
    resizeMode: "contain",
    backgroundColor: "#ffffff",
  },
  ios: {
    supportsTablet: true,
    bundleIdentifier: "com.example.myapp",
  },
  android: {
    adaptiveIcon: {
      foregroundImage: "./assets/adaptive-icon.png",
      backgroundColor: "#ffffff",
    },
    package: "com.example.myapp",
  },
  plugins: [
    "expo-secure-store",
    [
      "expo-notifications",
      { icon: "./assets/notification-icon.png", color: "#111111" },
    ],
  ],
  extra: {
    apiUrl: process.env.EXPO_PUBLIC_API_URL,
    eas: { projectId: "your-project-id" },
  },
};

export default config;
```

## ⚠️ Pitfalls [#️-pitfalls]

* Changing package / bundle ID after store release without a migration plan.
* Secrets in `extra` or public env vars.
* Plugin options ignored until the next native rebuild.

## 🔗 Related [#-related]

* [plugins.md](/docs/react-native/expo/plugins) — config plugins
* [build.md](/docs/react-native/expo/build) — applying config in builds
* [filestructure.md](/docs/react-native/expo/filestructure) — where config lives
* [commands.md](/docs/react-native/expo/commands) — `expo config`


---

# Constants (/docs/react-native/expo/constants)



# Constants [#constants]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

**`expo-constants`** exposes app metadata from the native manifest / config: version, `expoConfig`, installation id (where available), and EAS project fields. Use for feature flags wiring, update URLs, and debugging—not for secrets.

## 🔧 Core concepts [#-core-concepts]

| Field                                     | Role                               |
| ----------------------------------------- | ---------------------------------- |
| `Constants.expoConfig`                    | App config (name, slug, extra, …)  |
| `Constants.easConfig`                     | EAS ids when present               |
| `nativeAppVersion` / `nativeBuildVersion` | Store versions                     |
| `executionEnvironment`                    | storeClient / standalone / …       |
| `appOwnership`                            | expo / standalone (legacy nuances) |

`extra` comes from `app.config` → `expo.extra`.

## 💡 Examples [#-examples]

```tsx
import Constants from "expo-constants";
import { Text } from "react-native";

export function BuildStamp() {
  const version = Constants.expoConfig?.version ?? "dev";
  const projectId =
    Constants.expoConfig?.extra?.eas?.projectId ??
    Constants.easConfig?.projectId;
  return (
    <Text>
      v{version} · {projectId ?? "no-project"}
    </Text>
  );
}

export function apiBaseUrl() {
  return (
    Constants.expoConfig?.extra?.apiUrl ??
    process.env.EXPO_PUBLIC_API_URL ??
    ""
  );
}
```

```ts
// app.config.ts
extra: {
  apiUrl: process.env.EXPO_PUBLIC_API_URL,
  eas: { projectId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" },
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Putting secrets in `extra` (shipped in the binary).
* Assuming `manifest` legacy fields on new SDKs—prefer `expoConfig`.
* Using Constants for values that change per environment without rebuild/update.
* Null access before config is available—optional chain.

## 🔗 Related [#-related]

* [config.md](/docs/react-native/expo/config) — app config
* [updates\_ota.md](/docs/react-native/expo/updates-ota) — projectId
* [notifications\_expo.md](/docs/react-native/expo/notifications-expo) — push tokens
* [build.md](/docs/react-native/expo/build) — versioning
* [env](/docs/react-native/expo/config) — EXPO\_PUBLIC\_\*


---

# EAS Submit (/docs/react-native/expo/eas-submit)



# EAS Submit [#eas-submit]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

**`eas submit`** uploads a build to App Store Connect or Google Play. Pair with `eas build` artifacts (local path or latest build on EAS). Configure credentials once; automate with CI profiles in `eas.json`.

## 🔧 Core concepts [#-core-concepts]

| Piece                     | Role                  |
| ------------------------- | --------------------- |
| `eas submit -p ios`       | ASC upload            |
| `eas submit -p android`   | Play upload           |
| `eas.json` submit profile | Track, release status |
| ASC API key / Apple ID    | iOS auth              |
| Google service account    | Play API JSON         |
| `--latest`                | Use latest EAS build  |

Submit ≠ review: you still complete store listing / review in consoles.

## 💡 Examples [#-examples]

```json
// eas.json (excerpt)
{
  "cli": { "version": ">= 12.0.0" },
  "build": {
    "production": { "channel": "production" }
  },
  "submit": {
    "production": {
      "ios": {
        "ascAppId": "1234567890"
      },
      "android": {
        "serviceAccountKeyPath": "./play-service-account.json",
        "track": "internal"
      }
    }
  }
}
```

```shellscript
eas build -p ios --profile production
eas submit -p ios --profile production --latest

eas build -p android --profile production
eas submit -p android --profile production --path ./app-release.aab
```

## ⚠️ Pitfalls [#️-pitfalls]

* Submitting a build with wrong version/build number.
* Committing Play/ASC private keys to git.
* Using `production` track before internal testing.
* Assuming submit publishes immediately—manual rollout/review may remain.

## 🔗 Related [#-related]

* [build.md](/docs/react-native/expo/build) — EAS Build
* [keystore\_sign.md](/docs/react-native/expo/keystore-sign) — Android signing
* [updates\_ota.md](/docs/react-native/expo/updates-ota) — JS updates vs binaries
* [commands.md](/docs/react-native/expo/commands) — CLI
* [config.md](/docs/react-native/expo/config) — version / bundle ids


---

# File structure (/docs/react-native/expo/filestructure)



# File structure [#file-structure]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Expo apps are mostly JS/TS under the project root (or `src/`), with config at the top level. Native `ios/` / `android/` appear after **prebuild** or in bare workflows; prefer Continuous Native Generation + plugins over hand-editing when possible.

## 🔧 Core concepts [#-core-concepts]

* **Entry** — `package.json` `"main"` → `expo-router/entry` or `node_modules/expo/AppEntry.js`.
* **Router** — Expo Router uses `app/` file-based routes.
* **Assets** — `assets/` for icons, splash, fonts.
* **Config** — `app.config.ts`, `eas.json`, `babel.config.js`, `metro.config.js`.
* **Native** — generated `ios/`, `android/` (gitignore in managed CNG setups).

## 💡 Examples [#-examples]

```plaintext
MyApp/
  app/                 # Expo Router screens
    _layout.tsx
    index.tsx
    settings.tsx
  assets/
    icon.png
    splash.png
  src/
    components/
    lib/
  app.config.ts
  eas.json
  package.json
  tsconfig.json
  # after prebuild:
  ios/
  android/
```

```json
// package.json (Router)
{
  "main": "expo-router/entry",
  "scripts": {
    "start": "expo start",
    "android": "expo run:android",
    "ios": "expo run:ios"
  }
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Committing generated native projects while also relying on prebuild — pick a workflow.
* Putting screens outside `app/` when using Expo Router without registering them.
* Huge `assets/` without compression → install size.

## 🔗 Related [#-related]

* [config.md](/docs/react-native/expo/config) — app config
* [commands.md](/docs/react-native/expo/commands) — prebuild / start
* [plugins.md](/docs/react-native/expo/plugins) — native customization
* [build.md](/docs/react-native/expo/build) — CI builds


---

# Gradle (/docs/react-native/expo/gradle)



# Gradle [#gradle]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Android builds use **Gradle** inside `android/` (after prebuild) or on EAS builders. Expo abstracts most of this; touch Gradle for custom native modules, packaging options, or troubleshooting.

## 🔧 Core concepts [#-core-concepts]

* **Root** — `android/build.gradle`, `android/settings.gradle`, `gradle.properties`.
* **App module** — `android/app/build.gradle` (`applicationId`, signing, `minSdk`).
* **Expo autolinking** — native modules linked via Expo / RN Gradle plugins.
* **Properties** — `org.gradle.jvmargs`, `hermesEnabled`, architectures.
* **EAS** — cloud images run Gradle; override via `eas.json` env / `expo-build-properties` plugin.

## 💡 Examples [#-examples]

```ts
// app.config.ts — prefer plugin over hand-editing Gradle
plugins: [
  [
    "expo-build-properties",
    {
      android: {
        minSdkVersion: 24,
        compileSdkVersion: 35,
        targetSdkVersion: 35,
        kotlinVersion: "1.9.24",
      },
    },
  ],
],
```

```properties
# android/gradle.properties (generated — customize via plugins when possible)
hermesEnabled=true
newArchEnabled=true
```

```shellscript
cd android && ./gradlew assembleRelease
# or via Expo
npx expo run:android --variant release
```

## ⚠️ Pitfalls [#️-pitfalls]

* Manual Gradle edits wiped by `expo prebuild --clean` unless reflected in config plugins.
* Mismatched JDK / AGP versions vs Expo SDK expectations.
* Enabling New Architecture without compatible libraries.

## 🔗 Related [#-related]

* [build.md](/docs/react-native/expo/build) — EAS Android builds
* [keystore\_sign.md](/docs/react-native/expo/keystore-sign) — signing configs
* [plugins.md](/docs/react-native/expo/plugins) — build-properties plugin
* [commands.md](/docs/react-native/expo/commands) — `expo run:android`


---

# Image Picker (/docs/react-native/expo/image-picker)



# Image Picker [#image-picker]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

**`expo-image-picker`** launches the system gallery or camera to pick images/videos. Request media permissions, then `launchImageLibraryAsync` / `launchCameraAsync`. Returns local `uri`s for upload or display.

## 🔧 Core concepts [#-core-concepts]

| API                                   | Role                                                                |
| ------------------------------------- | ------------------------------------------------------------------- |
| `requestMediaLibraryPermissionsAsync` | Gallery                                                             |
| `requestCameraPermissionsAsync`       | Camera                                                              |
| `launchImageLibraryAsync`             | Pick existing                                                       |
| `launchCameraAsync`                   | Capture                                                             |
| Options                               | `mediaTypes`, `allowsEditing`, `quality`, `allowsMultipleSelection` |

Config plugin for photos permission strings.

## 💡 Examples [#-examples]

```tsx
import * as ImagePicker from "expo-image-picker";
import { useState } from "react";
import { Image, Pressable, Text } from "react-native";

export function AvatarPicker() {
  const [uri, setUri] = useState<string | null>(null);

  async function pick() {
    const perm = await ImagePicker.requestMediaLibraryPermissionsAsync();
    if (!perm.granted) return;
    const result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ["images"],
      allowsEditing: true,
      aspect: [1, 1],
      quality: 0.8,
    });
    if (!result.canceled) setUri(result.assets[0]?.uri ?? null);
  }

  return (
    <>
      <Pressable onPress={pick}>
        <Text>Choose photo</Text>
      </Pressable>
      {uri ? (
        <Image source={{ uri }} style={{ width: 96, height: 96 }} />
      ) : null}
    </>
  );
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Using deprecated `MediaTypeOptions` enums on newer SDKs—prefer `mediaTypes` arrays.
* Ignoring `canceled` results.
* Uploading full-resolution images without compression.
* Missing Info.plist / Android permission messages.

## 🔗 Related [#-related]

* [../camera.md](/docs/react-native/camera) — live camera
* [../image.md](/docs/react-native/image) — display
* [../permissions.md](/docs/react-native/permissions) — permission UX
* [config.md](/docs/react-native/expo/config) — plugins
* [secure\_store.md](/docs/react-native/expo/secure-store) — not for images


---

# Keystore & signing (/docs/react-native/expo/keystore-sign)



# Keystore & signing [#keystore--signing]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Android release builds must be **signed** with an upload/app signing keystore. EAS can generate and store credentials; Play App Signing uses Google’s key for distribution while you keep an upload key.

## 🔧 Core concepts [#-core-concepts]

* **Keystore** — `.jks` / `.keystore` with alias + passwords.
* **EAS-managed** — default for new projects; downloadable via `eas credentials`.
* **Local signing** — `android/app` signingConfigs for local release builds.
* **iOS counterpart** — distribution cert + provisioning profile (also via EAS).
* **Backup** — losing the upload key complicates Play updates (recovery possible with Play App Signing).

## 💡 Examples [#-examples]

```shellscript
# Inspect / manage credentials
npx eas-cli credentials -p android

# Production build (EAS uses stored keystore)
npx eas-cli build -p android --profile production
```

```json
// eas.json — credentialsSource
{
  "build": {
    "production": {
      "android": {
        "credentialsSource": "remote"
      }
    }
  }
}
```

```groovy
// Local sketch — prefer EAS; only for bare local releases
android {
  signingConfigs {
    release {
      storeFile file("release.keystore")
      storePassword System.getenv("KEYSTORE_PASSWORD")
      keyAlias System.getenv("KEY_ALIAS")
      keyPassword System.getenv("KEY_PASSWORD")
    }
  }
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Committing keystores or passwords to git.
* Creating a new keystore for an existing Play listing without updating upload key.
* Mixing debug and release signing when testing IAP / push.

## 🔗 Related [#-related]

* [build.md](/docs/react-native/expo/build) — release builds
* [gradle.md](/docs/react-native/expo/gradle) — Android build system
* [commands.md](/docs/react-native/expo/commands) — `eas credentials`
* [config.md](/docs/react-native/expo/config) — package name must stay stable


---

# Linking (Expo) (/docs/react-native/expo/linking-expo)



# Linking (Expo) [#linking-expo]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Expo linking builds on RN `Linking&#x60; with &#x2A;*`expo-linking`** helpers and Expo Router path integration. Set `scheme` in app config; use universal links / app links for https. Create URLs with `Linking.createURL` for consistent env behavior.

## 🔧 Core concepts [#-core-concepts]

| Piece           | Role                                 |
| --------------- | ------------------------------------ |
| `scheme`        | Custom URL scheme in config          |
| `createURL`     | Build deep link for current env      |
| `parse`         | Parse path/query                     |
| Expo Router     | File paths map to URLs               |
| Universal links | `associatedDomains` / intent filters |

Dev client / Go vs production URLs differ—`createURL` helps.

## 💡 Examples [#-examples]

```tsx
import * as Linking from "expo-linking";
import { useEffect } from "react";
import { router } from "expo-router";

const prefix = Linking.createURL("/");

export function useDeepLinks() {
  useEffect(() => {
    function handle(url: string) {
      const { path, queryParams } = Linking.parse(url);
      if (path?.startsWith("post/")) {
        router.push(`/post/${queryParams?.id ?? ""}`);
      }
    }
    Linking.getInitialURL().then((url) => url && handle(url));
    const sub = Linking.addEventListener("url", ({ url }) => handle(url));
    return () => sub.remove();
  }, []);
}

export function shareLink(id: string) {
  return Linking.createURL(`/post/${id}`);
}
```

```json
{
  "expo": {
    "scheme": "myapp",
    "ios": { "associatedDomains": ["applinks:example.com"] },
    "android": {
      "intentFilters": [
        {
          "action": "VIEW",
          "autoVerify": true,
          "data": [{ "scheme": "https", "host": "example.com", "pathPrefix": "/" }],
          "category": ["BROWSABLE", "DEFAULT"]
        }
      ]
    }
  }
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Hardcoding `myapp://` without `createURL` (breaks in Expo Go).
* Missing AASA / assetlinks verification for https links.
* Not testing cold start (`getInitialURL`).
* Scheme typos between config and marketing links.

## 🔗 Related [#-related]

* [router.md](/docs/react-native/expo/router) — Expo Router
* [config.md](/docs/react-native/expo/config) — scheme
* [../linking.md](/docs/react-native/linking) — RN Linking
* [../deeplinking.md](/docs/react-native/deeplinking) — deep links
* [../navigation.md](/docs/react-native/navigation) — navigation linking


---

# Notifications (Expo) (/docs/react-native/expo/notifications-expo)



# Notifications (Expo) [#notifications-expo]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

**`expo-notifications`** handles local notifications, push permission, device push tokens, and listeners. Push delivery uses Expo push service or raw FCM/APNs. Configure icons/sounds via config plugin; request permissions at a sensible moment.

## 🔧 Core concepts [#-core-concepts]

| Piece          | Role                               |
| -------------- | ---------------------------------- |
| Permissions    | `requestPermissionsAsync`          |
| Device token   | `getExpoPushTokenAsync`            |
| Local schedule | `scheduleNotificationAsync`        |
| Listeners      | received / response (tap)          |
| Channels       | Android notification channels      |
| Plugin         | `expo-notifications` in `app.json` |

Physical device required for remote push.

## 💡 Examples [#-examples]

```tsx
import { useEffect, useRef } from "react";
import * as Notifications from "expo-notifications";
import Constants from "expo-constants";
import { Platform } from "react-native";

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowBanner: true,
    shouldShowList: true,
    shouldPlaySound: false,
    shouldSetBadge: false,
  }),
});

export async function registerForPush() {
  const { status } = await Notifications.requestPermissionsAsync();
  if (status !== "granted") return null;
  if (Platform.OS === "android") {
    await Notifications.setNotificationChannelAsync("default", {
      name: "default",
      importance: Notifications.AndroidImportance.DEFAULT,
    });
  }
  const projectId =
    Constants.expoConfig?.extra?.eas?.projectId ??
    Constants.easConfig?.projectId;
  return Notifications.getExpoPushTokenAsync({ projectId });
}

export function useNotificationObserver() {
  const responseListener = useRef<Notifications.EventSubscription | null>(null);
  useEffect(() => {
    responseListener.current =
      Notifications.addNotificationResponseReceivedListener((response) => {
        console.log(response.notification.request.content.data);
      });
    return () => responseListener.current?.remove();
  }, []);
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Testing push on simulator/emulator without support.
* Missing EAS `projectId` for Expo tokens.
* Not creating Android channels → silent/wrong importance.
* Asking permission on first launch without context.

## 🔗 Related [#-related]

* [config.md](/docs/react-native/expo/config) — plugin / projectId
* [../notification.md](/docs/react-native/notification) — general notes
* [../permissions.md](/docs/react-native/permissions) — permission UX
* [linking\_expo.md](/docs/react-native/expo/linking-expo) — open from tap
* [constants.md](/docs/react-native/expo/constants) — project config


---

# Plugins (/docs/react-native/expo/plugins)



# Plugins [#plugins]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

**Config plugins** are JS functions that modify native projects during **prebuild**. They let managed/CNG apps add permissions, activities, Podfile changes, and Gradle tweaks without maintaining permanent `ios/` / `android/` forks.

## 🔧 Core concepts [#-core-concepts]

* **Declaration** — `plugins` array in `app.config`.
* **With options** — `["expo-camera", \{ cameraPermission: "..." \}]`.
* **Autolinking** — many `expo-*` packages ship a plugin; still list them when options are required.
* **Custom plugins** — `plugins/withMyNativeChange.js` using `@expo/config-plugins` mods.
* **Apply** — changes take effect on next `prebuild` / EAS Build, not in Expo Go unless the feature is already in the client.

## 💡 Examples [#-examples]

```ts
// app.config.ts
export default {
  expo: {
    plugins: [
      [
        "expo-camera",
        {
          cameraPermission: "Allow MyApp to take photos",
          microphonePermission: "Allow MyApp to record audio",
          recordAudioAndroid: true,
        },
      ],
      "expo-secure-store",
      ["./plugins/withAndroidQueries", { packages: ["com.android.vending"] }],
    ],
  },
};
```

```js
// plugins/withAndroidQueries.js
const { withAndroidManifest } = require("@expo/config-plugins");

function withAndroidQueries(config, { packages = [] }) {
  return withAndroidManifest(config, (cfg) => {
    const manifest = cfg.modResults.manifest;
    // mutate queries / intents as needed
    void packages;
    return cfg;
  });
}

module.exports = withAndroidQueries;
```

## ⚠️ Pitfalls [#️-pitfalls]

* Expecting plugin native changes inside Expo Go — need a **dev client** or store build.
* Forgetting to rebuild after adding a plugin.
* Hand-editing `ios/`/`android/` then losing changes on `--clean` prebuild.

## 🔗 Related [#-related]

* [config.md](/docs/react-native/expo/config) — where plugins are listed
* [build.md](/docs/react-native/expo/build) — builds apply plugins
* [commands.md](/docs/react-native/expo/commands) — prebuild
* [gradle.md](/docs/react-native/expo/gradle) — Android mods


---

# Router (/docs/react-native/expo/router)



# Router [#router]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

**Expo Router** is a file-based router built on React Navigation. Files under `app/` become routes; layouts wrap segments; deep links match paths. Use typed routes and `Link` / `router` for navigation.

## 🔧 Core concepts [#-core-concepts]

| Piece                  | Role                           |
| ---------------------- | ------------------------------ |
| `app/_layout.tsx`      | Root layout                    |
| `app/index.tsx`        | `/`                            |
| `app/[id].tsx`         | Dynamic segment                |
| `(groups)`             | Organizational, no URL segment |
| `Link` / `router.push` | Navigation                     |
| `Stack` / `Tabs`       | Navigators in layouts          |
| `+not-found`           | 404                            |

Enable plugin `"expo-router"` in app config; entry via `expo-router/entry`.

## 💡 Examples [#-examples]

```tsx
// app/_layout.tsx
import { Stack } from "expo-router";

export default function Layout() {
  return (
    <Stack>
      <Stack.Screen name="index" options={{ title: "Home" }} />
      <Stack.Screen name="post/[id]" options={{ title: "Post" }} />
    </Stack>
  );
}
```

```tsx
// app/index.tsx
import { Link } from "expo-router";
import { Text, View } from "react-native";

export default function Home() {
  return (
    <View>
      <Link href="/post/42">Open post</Link>
    </View>
  );
}
```

```tsx
// app/post/[id].tsx
import { useLocalSearchParams, router } from "expo-router";
import { Pressable, Text } from "react-native";

export default function Post() {
  const { id } = useLocalSearchParams<{ id: string }>();
  return (
    <>
      <Text>Post {id}</Text>
      <Pressable onPress={() => router.back()}>
        <Text>Back</Text>
      </Pressable>
    </>
  );
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Mixing React Navigation containers manually with Expo Router.
* Wrong folder names → unexpected URLs.
* Forgetting `scheme` in config for deep links.
* Heavy work in root layout blocking all screens.

## 🔗 Related [#-related]

* [config.md](/docs/react-native/expo/config) — scheme / plugins
* [linking\_expo.md](/docs/react-native/expo/linking-expo) — deep links
* [filestructure.md](/docs/react-native/expo/filestructure) — app dir
* [../navigation.md](/docs/react-native/navigation) — React Navigation concepts
* [../deeplinking.md](/docs/react-native/deeplinking) — native linking


---

# Secure Store (/docs/react-native/expo/secure-store)



# Secure Store [#secure-store]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

**`expo-secure-store`** stores small secrets in iOS Keychain / Android Keystore. Use for tokens and keys—not large blobs. AsyncStorage is not secure. Configure the config plugin when required by your SDK version.

## 🔧 Core concepts [#-core-concepts]

| API                        | Role                                          |
| -------------------------- | --------------------------------------------- |
| `setItemAsync(key, value)` | Save                                          |
| `getItemAsync(key)`        | Read                                          |
| `deleteItemAsync(key)`     | Remove                                        |
| Options                    | `keychainAccessible`, biometrics auth options |

Size limits apply; errors on unavailable hardware/secure lock screen policies.

## 💡 Examples [#-examples]

```tsx
import * as SecureStore from "expo-secure-store";

const TOKEN_KEY = "session_token";

export async function saveToken(token: string) {
  await SecureStore.setItemAsync(TOKEN_KEY, token);
}

export async function loadToken() {
  return SecureStore.getItemAsync(TOKEN_KEY);
}

export async function clearToken() {
  await SecureStore.deleteItemAsync(TOKEN_KEY);
}
```

**With auth prompt (when supported):**

```tsx
await SecureStore.setItemAsync("pin", value, {
  requireAuthentication: true,
  authenticationPrompt: "Unlock secrets",
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Storing JWTs in AsyncStorage instead.
* Large JSON documents—use file encryption or server.
* Assuming values survive app uninstall (platform-specific).
* Missing error handling when device is locked / biometrics fail.

## 🔗 Related [#-related]

* [../biometrics.md](/docs/react-native/biometrics) — local auth
* [../storage.md](/docs/react-native/storage) — insecure storage
* [config.md](/docs/react-native/expo/config) — plugins
* [../appstate.md](/docs/react-native/appstate) — lock on background
* [plugins.md](/docs/react-native/expo/plugins) — native config


---

# Updates (OTA) (/docs/react-native/expo/updates-ota)



# Updates (OTA) [#updates-ota]

*Expo · Reference cheat sheet*

***

## 📋 Overview [#-overview]

**EAS Update** delivers JavaScript/asset over-the-air updates without a full store release—when native code is unchanged. Configure `expo-updates`, publish with `eas update`, and channel/branch to builds. Native module changes still need a new binary.

## 🔧 Core concepts [#-core-concepts]

| Piece           | Role                                |
| --------------- | ----------------------------------- |
| Runtime version | Compatibility gate with binaries    |
| Channel         | Maps builds → update stream         |
| Branch          | Git-like update stream              |
| `expo-updates`  | Fetch/apply JS bundles              |
| Rollback        | Republish previous / serve rollback |

Policies: check on launch, reload when appropriate.

## 💡 Examples [#-examples]

```json
// app.json (excerpt)
{
  "expo": {
    "runtimeVersion": { "policy": "appVersion" },
    "updates": {
      "url": "https://u.expo.dev/<project-id>"
    },
    "extra": {
      "eas": { "projectId": "<project-id>" }
    }
  }
}
```

```shellscript
eas update --branch production --message "Fix checkout copy"
eas update:list --branch production
```

```tsx
import * as Updates from "expo-updates";
import { useEffect } from "react";

export function useApplyUpdate() {
  useEffect(() => {
    (async () => {
      if (__DEV__) return;
      const result = await Updates.checkForUpdateAsync();
      if (result.isAvailable) {
        await Updates.fetchUpdateAsync();
        await Updates.reloadAsync();
      }
    })();
  }, []);
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Shipping native changes via OTA—won't load; binary required.
* Mismatched `runtimeVersion` → updates ignored.
* Forcing reload mid-checkout without UX.
* Testing only in dev (Updates disabled in `__DEV__`).

## 🔗 Related [#-related]

* [build.md](/docs/react-native/expo/build) — binaries
* [config.md](/docs/react-native/expo/config) — updates URL
* [eas\_submit.md](/docs/react-native/expo/eas-submit) — store submit
* [commands.md](/docs/react-native/expo/commands) — EAS CLI
* [plugins.md](/docs/react-native/expo/plugins) — native config


---

# FlatList (/docs/react-native/flatlist)



# FlatList [#flatlist]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`FlatList` efficiently renders long scrolling lists by virtualizing off-screen rows. Provide `data`, `renderItem`, and a stable `keyExtractor`. For sectioned data use `SectionList`; for very large lists consider FlashList.

## 🔧 Core concepts [#-core-concepts]

| Prop                                | Role                         |
| ----------------------------------- | ---------------------------- |
| `data`                              | Array of items               |
| `renderItem`                        | Row renderer                 |
| `keyExtractor`                      | Stable keys                  |
| `ItemSeparatorComponent`            | Dividers                     |
| `ListHeaderComponent` / `Footer`    | Chrome                       |
| `onEndReached`                      | Infinite scroll              |
| `refreshing` / `onRefresh`          | Pull to refresh              |
| `getItemLayout`                     | Skip measure if fixed height |
| `windowSize` / `initialNumToRender` | Tuning                       |

Avoid anonymous inline components that remount every parent render—extract `Row`.

## 💡 Examples [#-examples]

```tsx
import { FlatList, Text, View, StyleSheet } from "react-native";

type Item = { id: string; title: string };

export function Feed({ items }: { items: Item[] }) {
  return (
    <FlatList
      data={items}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => (
        <View style={styles.row}>
          <Text>{item.title}</Text>
        </View>
      )}
      ItemSeparatorComponent={() => <View style={styles.sep} />}
      onEndReachedThreshold={0.4}
      onEndReached={() => {
        /* load more */
      }}
    />
  );
}

const styles = StyleSheet.create({
  row: { padding: 16 },
  sep: { height: 1, backgroundColor: "#eee" },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Using `ScrollView` + `.map` for huge lists.
* Inline `renderItem=\{() => ...\}` creating new types + unstable handlers without care.
* Missing keys / using index when reordering.
* Nesting VirtualizedLists (FlatList inside ScrollView) without care.
* Heavy rows—memoize row components.

## 🔗 Related [#-related]

* [sectionlist.md](/docs/react-native/sectionlist) — sections
* [scrollview.md](/docs/react-native/scrollview) — non-virtualized
* [refresh\_control.md](/docs/react-native/refresh-control) — pull to refresh
* [performance](/docs/react-native/../react/performance) — list perf
* [keys\_lists](/docs/react-native/../react/keys-lists) — identity


---

# Gesture (/docs/react-native/gesture)



# Gesture [#gesture]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Handle touches beyond simple presses with **React Native Gesture Handler** + **Reanimated**. Prefer RNGH over the old PanResponder for modern apps.

## 🔧 Core concepts [#-core-concepts]

* **`GestureDetector` + `Gesture`** — tap, pan, pinch, long press, race/simultaneous.
* **Root** — wrap app in `GestureHandlerRootView`.
* **Pressable / Touchable** — from `react-native-gesture-handler` inside navigators.
* **Native driver / UI thread** — update shared values in gesture callbacks.

## 💡 Examples [#-examples]

```tsx
import { Gesture, GestureDetector, GestureHandlerRootView } from "react-native-gesture-handler";
import Animated, { useSharedValue, useAnimatedStyle } from "react-native-reanimated";

export function Draggable() {
  const x = useSharedValue(0);
  const y = useSharedValue(0);
  const pan = Gesture.Pan().onChange((e) => {
    x.value += e.changeX;
    y.value += e.changeY;
  });
  const style = useAnimatedStyle(() => ({
    transform: [{ translateX: x.value }, { translateY: y.value }],
  }));

  return (
    <GestureDetector gesture={pan}>
      <Animated.View style={[{ width: 80, height: 80, backgroundColor: "#333" }, style]} />
    </GestureDetector>
  );
}

export function App() {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <Draggable />
    </GestureHandlerRootView>
  );
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Missing `GestureHandlerRootView` → gestures silently fail.
* Mixing RN `Touchable*` inside RNGH navigators without RNGH replacements.
* Gesture fights with `ScrollView` — use `simultaneousWithExternalGesture` / `native` gesture carefully.

## 🔗 Related [#-related]

* [touchable.md](/docs/react-native/touchable) — simple presses
* [animation.md](/docs/react-native/animation) — animated values
* [drawer.md](/docs/react-native/drawer) — drawer swipes
* [transition.md](/docs/react-native/transition) — interactive transitions


---

# Getting Started with React Native (/docs/react-native/getting-started)



# Getting Started with React Native [#getting-started-with-react-native]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

React Native (RN) lets you build mobile apps with React. Instead of HTML tags (`div`, `p`), you use native components (`View`, `Text`). One codebase can target iOS and Android (and web via React Native for Web).

## 🔧 Core concepts [#-core-concepts]

| Idea              | Meaning                                                                |
| ----------------- | ---------------------------------------------------------------------- |
| Native components | `View`, `Text`, `Image`, `Pressable`, …                                |
| StyleSheet        | JS objects for styling (Flexbox by default)                            |
| Metro / Expo      | Bundlers & tooling for RN apps                                         |
| Expo              | Beginner-friendly way to start without Xcode/Android Studio on day one |
| Platform APIs     | Camera, haptics, linking, etc. via modules                             |

**Recommended start:** Expo (`npx create-expo-app`).

## 💡 Examples [#-examples]

**Create an Expo app:**

```shellscript
npx create-expo-app@latest MyApp
cd MyApp
npx expo start
```

**Core imports:**

```jsx
import { View, Text, StyleSheet } from "react-native";

export default function App() {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Hello, React Native</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
  },
  title: { fontSize: 22 },
});
```

**Platform check:**

```jsx
import { Platform, Text } from "react-native";

<Text>Running on {Platform.OS}</Text>;
```

## ⚠️ Pitfalls [#️-pitfalls]

* There is no DOM — `document` / `div` / CSS files don’t apply the same way.
* All text must be inside `<Text>` — raw strings in `<View>` error.
* Flexbox defaults differ slightly from web (`flexDirection: "column"` by default).
* Testing on a real device needs the Expo Go app or a dev build.

## 🔗 Related [#-related]

* [hello\_world.md](/docs/react-native/hello-world)
* [reactnativeforweb.md](/docs/react-native/reactnativeforweb)
* [styling.md](/docs/react-native/styling)
* [pressable.md](/docs/react-native/pressable)


---

# Glossary (/docs/react-native/glossary)



# Glossary [#glossary]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Alphabetical glossary of core React Native terms for components, navigation, native modules, and mobile UI patterns.

## 🔧 Core concepts [#-core-concepts]

| Term              | Definition                                                                      |
| ----------------- | ------------------------------------------------------------------------------- |
| ActivityIndicator | A built-in spinner component for indeterminate loading states.                  |
| AppRegistry       | The JS entry that registers the root component with the native runtime.         |
| AppState          | An API reporting whether the app is active, background, or inactive.            |
| Bridge            | The legacy message channel between JavaScript and native modules.               |
| Dimensions        | An API that reads window or screen width and height.                            |
| Expo              | A toolchain and SDK that simplifies React Native development and builds.        |
| FlatList          | A performant scrolling list that virtualizes large data sets.                   |
| Flexbox           | The default layout system used by React Native styles.                          |
| Gesture           | Touch interaction handling, often via Gesture Handler or Pressable.             |
| Hermes            | A JavaScript engine optimized for React Native startup and memory.              |
| Linking           | An API for opening URLs and handling deep links into the app.                   |
| Metro             | The JavaScript bundler commonly used by React Native projects.                  |
| Modal             | A component that presents content above the current screen.                     |
| Native module     | Platform code (Swift/Kotlin/etc.) exposed to JavaScript.                        |
| Navigation        | Moving between screens, typically via React Navigation stacks/tabs.             |
| New Architecture  | Fabric renderer and TurboModules replacing the legacy bridge path.              |
| Platform          | Helpers to branch behavior for iOS, Android, or web.                            |
| Pressable         | A core component for detecting presses with fine-grained feedback.              |
| SafeAreaView      | A view that insets content away from notches and system UI.                     |
| ScrollView        | A scrollable container for content that fits reasonably in memory.              |
| SectionList       | A virtualized list organized into titled sections.                              |
| StatusBar         | Control over the system status bar style and visibility.                        |
| StyleSheet        | An API that creates optimized style objects for components.                     |
| TextInput         | A core editable text field component.                                           |
| Touchable         | Legacy press wrappers (`TouchableOpacity`, etc.) largely replaced by Pressable. |
| View              | The fundamental container component, analogous to a `div` on web.               |
| Yoga              | The cross-platform layout engine implementing Flexbox for native views.         |

## 💡 Examples [#-examples]

**View, Text, and StyleSheet:**

```tsx
import { StyleSheet, Text, View } from "react-native";

const styles = StyleSheet.create({
  box: { padding: 16, flex: 1 },
  title: { fontSize: 18, fontWeight: "600" },
});

export function Card() {
  return (
    <View style={styles.box}>
      <Text style={styles.title}>Hello</Text>
    </View>
  );
}
```

**FlatList:**

```tsx
<FlatList
  data={users}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => <Text>{item.name}</Text>}
/>
```

**AppState:**

```tsx
useEffect(() => {
  const sub = AppState.addEventListener("change", (next) => {
    console.log(next);
  });
  return () => sub.remove();
}, []);
```

## ⚠️ Pitfalls [#️-pitfalls]

* Confusing **ScrollView** (simple, all-in-memory) with **FlatList** (virtualized).
* Mixing web **CSS** assumptions with React Native **StyleSheet** — many properties differ.
* Treating **Touchable**\* and **Pressable** as identical — Pressable is the modern API.
* Assuming **Linking** alone equals full **navigation** — deep links still need a navigator.
* Equating **Expo** managed workflow with bare React Native — tooling and native access differ.

## 🔗 Related [#-related]

* [basic\_primitives](/docs/react-native/basic-primitives)
* [flatlist](/docs/react-native/flatlist)
* [navigation](/docs/react-native/navigation)
* [styling](/docs/react-native/styling)
* [appstate](/docs/react-native/appstate)
* [safe\_area](/docs/react-native/safe-area)


---

# Haptics (/docs/react-native/haptics)



# Haptics [#haptics]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Haptics provide nuanced tactile feedback (impact, notification, selection). In Expo use `expo-haptics`; in bare RN use platform modules or community packages. Prefer haptics over crude `Vibration` for UI polish—especially iOS.

## 🔧 Core concepts [#-core-concepts]

| Type         | When                      |
| ------------ | ------------------------- |
| Impact       | Light/medium/heavy taps   |
| Notification | Success / warning / error |
| Selection    | Picker ticks, toggles     |

Always no-op gracefully on unsupported hardware/simulators.

## 💡 Examples [#-examples]

```tsx
import * as Haptics from "expo-haptics";
import { Pressable, Text } from "react-native";

export function LikeButton({ onLike }: { onLike: () => void }) {
  return (
    <Pressable
      onPress={async () => {
        await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
        onLike();
      }}
    >
      <Text>Like</Text>
    </Pressable>
  );
}

export async function notifySuccess() {
  await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
}

export async function tick() {
  await Haptics.selectionAsync();
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Firing haptics on every scroll event—too noisy.
* Ignoring “Reduce Motion” / haptic disable preferences when available.
* Blocking UI on awaited haptics unnecessarily—fire-and-forget is fine.
* Assuming Android parity with iOS Taptic Engine.

## 🔗 Related [#-related]

* [vibration.md](/docs/react-native/vibration) — basic vibrate
* [pressable.md](/docs/react-native/pressable) — buttons
* [picker.md](/docs/react-native/picker) — selection ticks
* [gesture.md](/docs/react-native/gesture) — gesture feedback
* [touchable.md](/docs/react-native/touchable) — press handling


---

# Hello World (/docs/react-native/hello-world)



# Hello World [#hello-world]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

React Native Hello World shows text on a screen using `View` + `Text`. With Expo, you scan a QR code (Expo Go) or use an emulator to see the result live.

## 🔧 Core concepts [#-core-concepts]

| Piece               | Role                              |
| ------------------- | --------------------------------- |
| `App` / screen      | Root component Expo loads         |
| `View`              | Container (like a non-text `div`) |
| `Text`              | Renders strings                   |
| `StyleSheet.create` | Defines reusable styles           |
| Fast Refresh        | Saves reload UI as you edit       |

Keep the first screen tiny so tooling issues are obvious.

## 💡 Examples [#-examples]

**Minimal screen:**

```jsx
import { View, Text, StyleSheet } from "react-native";

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Hello, World!</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
});
```

**Styled greeting:**

```jsx
import { View, Text, StyleSheet } from "react-native";

export default function App() {
  const name = "Ada";
  return (
    <View style={styles.container}>
      <Text style={styles.hello}>Hello, {name}!</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: "center", alignItems: "center" },
  hello: { fontSize: 24, fontWeight: "600" },
});
```

**Pressable interaction:**

```jsx
import { useState } from "react";
import { Pressable, Text, View } from "react-native";

export default function App() {
  const [n, setN] = useState(0);
  return (
    <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
      <Pressable onPress={() => setN(n + 1)}>
        <Text>Hello taps: {n}</Text>
      </Pressable>
    </View>
  );
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Putting text directly in `View` without `Text` throws.
* Web CSS class names don’t apply — use style objects.
* Safe area / notches: later use `SafeAreaView` or safe-area libraries.
* If the bundle fails, read the Metro/Expo terminal error first.

## 🔗 Related [#-related]

* [getting\_started.md](/docs/react-native/getting-started)
* [reactnativeforweb.md](/docs/react-native/reactnativeforweb)
* [styling.md](/docs/react-native/styling)
* [pressable.md](/docs/react-native/pressable)


---

# Image (/docs/react-native/image)



# Image [#image]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`Image` displays local `require` assets or remote `\{ uri \}` sources. Set dimensions (or use `style` width/height); remote images need explicit size. Prefer `expo-image` for caching, blurhash, and better performance in Expo apps.

## 🔧 Core concepts [#-core-concepts]

| Topic         | Notes                                         |
| ------------- | --------------------------------------------- |
| Local         | `source=\{require("./pic.png")\}`             |
| Remote        | `source=\{\{ uri, headers? \}\}`              |
| Resize        | `resizeMode`: cover, contain, stretch, center |
| Events        | `onLoad`, `onError`                           |
| Prefetch      | `Image.prefetch(url)`                         |
| Accessibility | `accessibilityLabel` for meaningful images    |

Network security: HTTPS; ATS / cleartext rules on iOS/Android.

## 💡 Examples [#-examples]

```tsx
import { Image, StyleSheet, View } from "react-native";

export function Avatar({ url }: { url: string }) {
  return (
    <Image
      source={{ uri: url }}
      style={styles.avatar}
      resizeMode="cover"
      accessibilityLabel="Profile photo"
      onError={() => {
        /* fallback */
      }}
    />
  );
}

export function Logo() {
  return (
    <View>
      <Image source={require("../assets/logo.png")} style={styles.logo} />
    </View>
  );
}

const styles = StyleSheet.create({
  avatar: { width: 64, height: 64, borderRadius: 32 },
  logo: { width: 120, height: 40 },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Remote images without width/height → layout 0.
* Huge unoptimized assets in the bundle.
* Missing cache strategy for lists of remote images.
* Decorative images announced to VoiceOver—set `accessible=\{false\}` when appropriate.

## 🔗 Related [#-related]

* [styling.md](/docs/react-native/styling) — layout
* [Expo image\_picker](/docs/react-native/expo/image-picker) — picking
* [networking.md](/docs/react-native/networking) — remote assets
* [basic\_primitives.md](/docs/react-native/basic-primitives) — View/Text
* [permissions.md](/docs/react-native/permissions) — media library


---

# Keyboard (/docs/react-native/keyboard)



# Keyboard [#keyboard]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Manage soft keyboard visibility, dismissals, and layout shifts with `Keyboard`, `KeyboardAvoidingView`, and community libs like `keyboard-controller` / `react-native-keyboard-aware-scroll-view`.

## 🔧 Core concepts [#-core-concepts]

* **`Keyboard.dismiss()`** — hide keyboard.
* **Events** — `keyboardDidShow` / `keyboardDidHide` (platform naming differs for Will/Did).
* **`KeyboardAvoidingView`** — `behavior="padding"` (iOS) / often `"height"` or none on Android.
* **`keyboardShouldPersistTaps`** — on scroll views so taps register while keyboard is open.

## 💡 Examples [#-examples]

```tsx
import {
  Keyboard,
  KeyboardAvoidingView,
  Platform,
  Pressable,
  TextInput,
  StyleSheet,
} from "react-native";

export function ChatInput() {
  return (
    <KeyboardAvoidingView
      style={styles.flex}
      behavior={Platform.OS === "ios" ? "padding" : undefined}
      keyboardVerticalOffset={64}
    >
      <Pressable style={styles.flex} onPress={Keyboard.dismiss}>
        <TextInput placeholder="Message" style={styles.input} />
      </Pressable>
    </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  flex: { flex: 1 },
  input: { borderWidth: 1, margin: 16, padding: 12, borderRadius: 8 },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Double-avoiding (AvoidingView + manual padding) → huge gaps.
* Android `windowSoftInputMode` in manifest conflicting with JS avoidance.
* Forgetting `keyboardShouldPersistTaps="handled"` on forms in ScrollViews.

## 🔗 Related [#-related]

* [layout.md](/docs/react-native/layout) — flex + offsets
* [basic\_primitives.md](/docs/react-native/basic-primitives) — TextInput
* [modal.md](/docs/react-native/modal) — keyboard inside modals
* [platform\_specific.md](/docs/react-native/platform-specific) — iOS vs Android


---

# React Native Launcher Shortcuts (/docs/react-native/launcher-shortcut-menu)



# React Native Launcher Shortcuts [#react-native-launcher-shortcuts]

*React Native · Quick Reference*

***

## 📋 Overview [#-overview]

Android App Shortcuts allow users to long-press your app icon to access quick actions directly from the launcher. Supported on Android 7.1+ (API 25+).

***

## 🔧 Core Concepts [#-core-concepts]

| Shortcut Type | Description                                                            |
| ------------- | ---------------------------------------------------------------------- |
| **Static**    | Defined in `AndroidManifest.xml`, fixed at build time                  |
| **Dynamic**   | Added/removed at runtime via JavaScript                                |
| **Pinned**    | User manually pins to home screen (cannot be removed programmatically) |

***

## 🚀 Libraries [#-libraries]

### Recommended: `@rn-org/react-native-shortcuts` [#recommended-rn-orgreact-native-shortcuts]

```shellscript
npm install @rn-org/react-native-shortcuts
# or
yarn add @rn-org/react-native-shortcuts
```

### Alternative: `@mobigaurav/react-native-quick-actions` [#alternative-mobigauravreact-native-quick-actions]

```shellscript
npm install @mobigaurav/react-native-quick-actions
```

***

## 💡 Basic Implementation [#-basic-implementation]

### Check Support & Add Shortcuts [#check-support--add-shortcuts]

```tsx
import Shortcuts from '@rn-org/react-native-shortcuts'

// Check if supported (Android 7.1+)
const supported = await Shortcuts.isShortcutSupported()

// Add shortcuts
await Shortcuts.addShortcut({
  id: 'compose',
  title: 'Compose',
  longLabel: 'Start new message', // Max 25 chars
  iconName: 'ic_compose'          // Drawable resource name
})

await Shortcuts.addShortcut({
  id: 'search', 
  title: 'Search',
  iconName: 'ic_search'
})

// Remove all shortcuts
await Shortcuts.removeAllShortcuts()

// Remove specific shortcut
await Shortcuts.removeShortcut('compose')
```

### Handle Shortcut Navigation [#handle-shortcut-navigation]

```tsx
import { useEffect, useRef } from 'react'
import Shortcuts from '@rn-org/react-native-shortcuts'

function App() {
  // Handle initial launch via shortcut (cold start)
  useEffect(() => {
    const checkInitial = async () => {
      const id = await Shortcuts.getInitialShortcutId()
      if (id) navigateToShortcut(id)
    }
    checkInitial()
  }, [])

  // Handle shortcut when app is in background (warm start)
  useEffect(() => {
    const sub = Shortcuts.addOnShortcutUsedListener((id) => {
      navigateToShortcut(id)
    })
    return () => sub.remove()
  }, [])

  const navigateToShortcut = (id: string) => {
    switch(id) {
      case 'compose': navigation.navigate('Compose'); break
      case 'search': navigation.navigate('Search'); break
    }
  }

  return <YourApp />
}
```

***

## 🎨 Android Icons [#-android-icons]

Add icons to `android/app/src/main/res/drawable/`:

```
android/app/src/main/res/drawable/
  ├── ic_compose.xml      # Vector drawable
  ├── ic_search.png       # PNG image
  └── ic_settings.xml
```

**Requirements:**

* Material Design guidelines
* Vector (XML) preferred over raster (PNG)
* 48dp x 48dp recommended

***

## 📋 Android Manifest Setup [#-android-manifest-setup]

For **static** shortcuts (optional - pre-defined at build time):

```xml
<!-- android/app/src/main/AndroidManifest.xml -->
<application ...>
  <activity android:name=".MainActivity">
    <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

    <!-- Static shortcuts -->
    <meta-data
      android:name="android.app.shortcuts"
      android:resource="@xml/shortcuts" />
  </activity>
</application>
```

```xml
<!-- android/app/src/main/res/xml/shortcuts.xml -->
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
  <shortcut
    android:shortcutId="compose"
    android:enabled="true"
    android:icon="@drawable/ic_compose"
    android:shortcutShortLabel="Compose"
    android:shortcutLongLabel="Compose Message">
    <intent
      android:action="android.intent.action.VIEW"
      android:targetPackage="com.yourapp"
      android:targetClass="com.yourapp.MainActivity" />
    <categories android:name="android.shortcut.conversation" />
  </shortcut>
</shortcuts>
```

***

## ⚠️ Pitfalls [#️-pitfalls]

| Issue                                                   | Solution                                               |
| ------------------------------------------------------- | ------------------------------------------------------ |
| **Pinned shortcuts** cannot be removed programmatically | User must unpin manually                               |
| **4 shortcut limit** (dynamic + static)                 | Prioritize most used actions                           |
| **Launch mode issues**                                  | Check `android:launchMode` in manifest                 |
| **Icon not showing**                                    | Verify drawable resource exists and is correctly named |

***

## 🔗 Related [#-related]

* [deep\_linking.md](/docs/react-native/deep-linking) — Navigation from shortcuts
* [notifications.md](/docs/react-native/notifications) — Push notifications
* [keyboard.md](/docs/react-native/keyboard) — Keyboard handling

***

## 📚 Documentation [#-documentation]

* [Android App Shortcuts](https://developer.android.com/develop/ui/views/launch/shortcuts)
* [react-native-shortcuts](https://github.com/rn-org/react-native-shortcuts)
* [react-native-quick-actions](https://github.com/mobigaurav/react-native-quick-actions)


---

# Layout (/docs/react-native/layout)



# Layout [#layout]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Layout uses **Flexbox** (default `flexDirection: "column"`). Yoga implements flex on both platforms. Position with `flex`, alignment, margins/padding — not CSS Grid.

## 🔧 Core concepts [#-core-concepts]

* **Defaults** — column direction; `alignItems: stretch`.
* **Key props** — `flex`, `justifyContent`, `alignItems`, `alignSelf`, `gap` (newer RN).
* **Sizing** — numbers are density-independent pixels; `%` relative to parent.
* **Absolute** — `position: "absolute"` + `top`/`left`/`right`/`bottom`.
* **Safe area** — insets for notches / home indicator.

## 💡 Examples [#-examples]

```tsx
import { View, StyleSheet } from "react-native";

const styles = StyleSheet.create({
  screen: { flex: 1, padding: 16 },
  row: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" },
  card: { flex: 1, minHeight: 120, borderRadius: 12, backgroundColor: "#eee" },
  fab: {
    position: "absolute",
    right: 16,
    bottom: 16,
    width: 56,
    height: 56,
    borderRadius: 28,
  },
});

export function Screen() {
  return (
    <View style={styles.screen}>
      <View style={styles.row}>
        <View style={styles.card} />
        <View style={[styles.card, { marginLeft: 12 }]} />
      </View>
      <View style={[styles.fab, { backgroundColor: "#111" }]} />
    </View>
  );
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Web CSS habits (`display: block`, grid) don’t apply.
* Missing `flex: 1` on parents → children with flex don’t expand.
* Fixed widths that overflow small phones — prefer flex + `minWidth`/`maxWidth`.

## 🔗 Related [#-related]

* [basic\_primitives.md](/docs/react-native/basic-primitives) — View / Text
* [dimensions.md](/docs/react-native/dimensions) — window size
* [statusbar.md](/docs/react-native/statusbar) — top inset
* [animation.md](/docs/react-native/animation) — layout animations


---

# Linking (/docs/react-native/linking)



# Linking [#linking]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`Linking` opens URLs (https, tel, mailto, custom schemes) and listens for deep links that open the app. Configure schemes in native projects / `app.json`. For navigation integration, use React Navigation linking config or Expo Router.

## 🔧 Core concepts [#-core-concepts]

| API                       | Role                           |
| ------------------------- | ------------------------------ |
| `openURL`                 | Open external / custom URL     |
| `canOpenURL`              | Check handler (iOS LS queries) |
| `getInitialURL`           | Cold-start link                |
| `addEventListener('url')` | Warm links                     |
| `openSettings`            | App settings                   |

Universal Links / App Links need domain association files.

## 💡 Examples [#-examples]

```tsx
import { Linking, Pressable, Text, Alert } from "react-native";

async function openSupport() {
  const url = "mailto:support@example.com?subject=Help";
  const ok = await Linking.canOpenURL(url);
  if (!ok) {
    Alert.alert("No mail app available");
    return;
  }
  await Linking.openURL(url);
}

export function SupportLink() {
  return (
    <Pressable onPress={openSupport}>
      <Text>Email support</Text>
    </Pressable>
  );
}
```

**Listen for URLs:**

```tsx
import { useEffect } from "react";
import { Linking } from "react-native";

useEffect(() => {
  Linking.getInitialURL().then((url) => {
    if (url) handleUrl(url);
  });
  const sub = Linking.addEventListener("url", ({ url }) => handleUrl(url));
  return () => sub.remove();
}, []);
```

## ⚠️ Pitfalls [#️-pitfalls]

* iOS `canOpenURL` requires declared schemes in `LSApplicationQueriesSchemes`.
* Not handling both cold and warm start.
* Custom scheme collisions with other apps.
* Using Linking alone without mapping to navigation routes.

## 🔗 Related [#-related]

* [deeplinking.md](/docs/react-native/deeplinking) — deep link setup
* [navigation.md](/docs/react-native/navigation) — route mapping
* [Expo linking\_expo](/docs/react-native/expo/linking-expo) — Expo helpers
* [permissions.md](/docs/react-native/permissions) — settings
* [pressable.md](/docs/react-native/pressable) — buttons


---

# Maps (/docs/react-native/maps)



# Maps [#maps]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Maps are typically &#x2A;*`react-native-maps`** (Google/Apple MapKit) or Expo-friendly wrappers. Show a region, markers, and user location (with permissions). API keys required for Google Maps on Android (and iOS if using Google).

## 🔧 Core concepts [#-core-concepts]

| Piece                 | Role                               |
| --------------------- | ---------------------------------- |
| `MapView`             | Map canvas                         |
| `Marker` / `Polyline` | Annotations                        |
| `region` / `camera`   | Viewport                           |
| `showsUserLocation`   | Blue dot (permission)              |
| Provider              | `PROVIDER_GOOGLE` vs default Apple |

Cluster markers for dense data; avoid re-creating marker arrays carelessly.

## 💡 Examples [#-examples]

```tsx
import MapView, { Marker, PROVIDER_GOOGLE } from "react-native-maps";
import { StyleSheet } from "react-native";

export function StoreMap() {
  return (
    <MapView
      style={styles.map}
      provider={PROVIDER_GOOGLE}
      initialRegion={{
        latitude: 37.78825,
        longitude: -122.4324,
        latitudeDelta: 0.05,
        longitudeDelta: 0.05,
      }}
    >
      <Marker
        coordinate={{ latitude: 37.78825, longitude: -122.4324 }}
        title="Store"
        description="Open 9–5"
      />
    </MapView>
  );
}

const styles = StyleSheet.create({
  map: { flex: 1 },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Missing Google Maps API key / billing → blank map.
* Tracking user location without purpose string / runtime permission.
* Animating region on every render.
* Huge numbers of markers without clustering.

## 🔗 Related [#-related]

* [permissions.md](/docs/react-native/permissions) — location
* [linking.md](/docs/react-native/linking) — open in Maps app
* [Expo config](/docs/react-native/expo/config) — keys / plugins
* [styling.md](/docs/react-native/styling) — layout
* [networking.md](/docs/react-native/networking) — geocoding APIs


---

# Modal (/docs/react-native/modal)



# Modal [#modal]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`Modal` presents content above the current screen (native modal host). For navigation-style modals, prefer a stack with `presentation: "modal"`.

## 🔧 Core concepts [#-core-concepts]

* **Props** — `visible`, `transparent`, `animationType` (`none` | `slide` | `fade`).
* **`onRequestClose`** — required on Android (back button).
* **Nesting** — avoid deep modal stacks; use navigation instead.
* **Accessibility** — focus trap / labels for dismiss controls.

## 💡 Examples [#-examples]

```tsx
import { Modal, View, Text, Pressable, StyleSheet } from "react-native";

export function ConfirmModal({
  open,
  onClose,
  message,
}: {
  open: boolean;
  onClose: () => void;
  message: string;
}) {
  return (
    <Modal
      visible={open}
      transparent
      animationType="fade"
      onRequestClose={onClose}
    >
      <View style={styles.backdrop}>
        <View style={styles.sheet}>
          <Text>{message}</Text>
          <Pressable onPress={onClose} accessibilityRole="button">
            <Text>Close</Text>
          </Pressable>
        </View>
      </View>
    </Modal>
  );
}

const styles = StyleSheet.create({
  backdrop: {
    flex: 1,
    backgroundColor: "rgba(0,0,0,0.5)",
    justifyContent: "center",
    padding: 24,
  },
  sheet: { backgroundColor: "#fff", borderRadius: 12, padding: 16 },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Missing `onRequestClose` on Android.
* Putting a Modal inside a view with `opacity` / transforms — weird clipping.
* Using Modal for every route — navigators scale better.

## 🔗 Related [#-related]

* [backhandler.md](/docs/react-native/backhandler) — Android back
* [keyboard.md](/docs/react-native/keyboard) — inputs in modals
* [transition.md](/docs/react-native/transition) — presentation motion
* [touchable.md](/docs/react-native/touchable) — dismiss controls


---

# Navigation (/docs/react-native/navigation)



# Navigation [#navigation]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

**React Navigation** is the standard stack for RN screens: native stack, bottom tabs, drawer. Define a navigator tree, pass params with types, and use hooks (`useNavigation`, `useRoute`). Expo Router is file-based on top of the same primitives—see Expo `router.md`.

## 🔧 Core concepts [#-core-concepts]

| Piece                 | Role                                   |
| --------------------- | -------------------------------------- |
| `NavigationContainer` | Root (bare RN; Expo Router wraps this) |
| Native Stack          | Push/pop screens                       |
| Tabs / Drawer         | Top-level IA                           |
| Params                | Typed route params                     |
| Linking               | Deep links ↔ routes                    |
| Nested navigators     | Independent histories                  |

Prefer `@react-navigation/native-stack` over JS stack for performance.

## 💡 Examples [#-examples]

```tsx
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";

type RootStackParamList = {
  Home: undefined;
  Details: { id: string };
};

const Stack = createNativeStackNavigator<RootStackParamList>();

export function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}
```

```tsx
import { useNavigation, useRoute } from "@react-navigation/native";
import type { NativeStackNavigationProp } from "@react-navigation/native-stack";
import type { RouteProp } from "@react-navigation/native";

function HomeScreen() {
  const navigation =
    useNavigation<NativeStackNavigationProp<RootStackParamList>>();
  return (
    <Pressable onPress={() => navigation.navigate("Details", { id: "1" })}>
      <Text>Open</Text>
    </Pressable>
  );
}

function DetailsScreen() {
  const route = useRoute<RouteProp<RootStackParamList, "Details">>();
  return <Text>{route.params.id}</Text>;
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Multiple `NavigationContainer`s without a clear root.
* Untyped params → runtime surprises.
* Heavy work in screen components that stay mounted in tabs.
* Ignoring deep linking / back behavior on Android.

## 🔗 Related [#-related]

* [touchable.md](/docs/react-native/touchable) — Pressable
* [deeplinking.md](/docs/react-native/deeplinking) — URL schemes
* [drawer.md](/docs/react-native/drawer) — drawer patterns
* [backhandler.md](/docs/react-native/backhandler) — Android back
* [Expo router](/docs/react-native/expo/router) — file-based routing


---

# Networking (/docs/react-native/networking)



# Networking [#networking]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

RN supports `fetch`, `XMLHttpRequest`, and WebSockets. Use HTTPS, handle offline, and prefer a thin API client (fetch wrapper, axios, ky, React Query).

## 🔧 Core concepts [#-core-concepts]

* **`fetch(url, init)`** — Promise-based; no timeout built-in.
* **JSON** — `res.json()`; set `Content-Type` on requests.
* **Auth** — attach tokens in headers; store securely (SecureStore / Keychain).
* **Dev** — Android cleartext / ATS exceptions only for local debug.
* **Abort** — `AbortController` to cancel on unmount.

## 💡 Examples [#-examples]

```tsx
async function getUser(id: string, signal?: AbortSignal) {
  const res = await fetch(`https://api.example.com/users/${id}`, {
    headers: { Accept: "application/json" },
    signal,
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json() as Promise<{ id: string; name: string }>;
}
```

```tsx
import { useEffect, useState } from "react";

export function useUser(id: string) {
  const [data, setData] = useState<{ name: string } | null>(null);
  useEffect(() => {
    const ctrl = new AbortController();
    getUser(id, ctrl.signal).then(setData).catch(() => {});
    return () => ctrl.abort();
  }, [id]);
  return data;
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* No network permission issues on iOS/Android for plain HTTPS — but ATS / cleartext can block HTTP.
* Ignoring non-2xx status — `fetch` only rejects on network failure.
* Leaking tokens in logs.

## 🔗 Related [#-related]

* [request.md](/docs/react-native/request) — request helpers
* [storage.md](/docs/react-native/storage) — token storage
* [permissions.md](/docs/react-native/permissions) — related OS permissions
* [notification.md](/docs/react-native/notification) — push payloads


---

# Notification (/docs/react-native/notification)



# Notification [#notification]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Local and push notifications need OS permission, device tokens, and a service (FCM / APNs). In Expo, use &#x2A;*`expo-notifications`** + EAS credentials; in bare RN, `@react-native-firebase/messaging` or Notifee are common.

## 🔧 Core concepts [#-core-concepts]

* **Permission** — request before scheduling / registering.
* **Channels (Android)** — create notification channels for importance.
* **Handlers** — foreground presentation; response (tap) → navigate / deep link.
* **Push tokens** — Expo push token or native FCM/APNs token → your backend.
* **EAS** — credentials for FCM / APNs managed via `eas credentials`.

## 💡 Examples [#-examples]

```tsx
import * as Notifications from "expo-notifications";
import { useEffect } from "react";
import { Platform } from "react-native";

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: false,
    shouldSetBadge: false,
  }),
});

export function useNotificationSetup() {
  useEffect(() => {
    (async () => {
      const { status } = await Notifications.requestPermissionsAsync();
      if (status !== "granted") return;
      if (Platform.OS === "android") {
        await Notifications.setNotificationChannelAsync("default", {
          name: "default",
          importance: Notifications.AndroidImportance.DEFAULT,
        });
      }
      const token = (await Notifications.getExpoPushTokenAsync()).data;
      // send token to backend
      console.log(token);
    })();
  }, []);
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Testing push on simulators — limited; use physical devices.
* Missing Android channels → silent / wrong importance.
* Not handling notification taps when app is killed (use last response API).

## 🔗 Related [#-related]

* [permissions.md](/docs/react-native/permissions) — permission flow
* [deeplinking.md](/docs/react-native/deeplinking) — open screens from taps
* [Expo/config.md](/docs/react-native/expo/config) — plugins / entitlements
* [Expo/build.md](/docs/react-native/expo/build) — store builds with push


---

# Notifications (/docs/react-native/notifications)



# Notifications [#notifications]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Local and push notifications alert users outside the app UI. On Expo, use `expo-notifications`; bare RN often uses Firebase / Notifee.

## 🔧 Core concepts [#-core-concepts]

| Piece       | Role                            |
| ----------- | ------------------------------- |
| Permissions | Request before scheduling       |
| Local       | Scheduled on-device             |
| Push        | Remote via FCM/APNs             |
| Handlers    | Foreground / response listeners |

## 💡 Examples [#-examples]

```tsx
import * as Notifications from 'expo-notifications';

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: false,
    shouldSetBadge: false,
    shouldShowBanner: true,
    shouldShowList: true,
  }),
});
```

```tsx
await Notifications.scheduleNotificationAsync({
  content: { title: 'Reminder', body: 'Ship the docs' },
  trigger: { type: Notifications.SchedulableTriggerInputTypes.TIME_INTERVAL, seconds: 5 },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* iOS requires explicit permission; Android 13+ needs POST\_NOTIFICATIONS.
* Don’t assume push tokens are stable forever.
* Handle notification taps to deep-link into the right screen.

## 🔗 Related [#-related]

* [deep\_linking](/docs/react-native/deep-linking)
* [launcher\_shortcut\_menu](/docs/react-native/launcher-shortcut-menu)
* [getting\_started](/docs/react-native/getting-started)


---

# Permissions (/docs/react-native/permissions)



# Permissions [#permissions]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Sensitive APIs (camera, photos, location, mic, notifications, tracking) require runtime permission prompts plus Info.plist / AndroidManifest declarations. Expo: `expo-*` modules + config plugins.

## 🔧 Core concepts [#-core-concepts]

* **Declare** — usage strings (`NSCameraUsageDescription`) and manifest permissions.
* **Request at need** — when the user taps an action, not on cold start spam.
* **Check status** — `granted` | `denied` | `undetermined` | limited (iOS photos).
* **Settings** — if denied, deep-link to app settings (`Linking.openSettings()`).
* **Expo** — `expo-camera`, `expo-location`, `expo-image-picker`, etc.

## 💡 Examples [#-examples]

```tsx
import * as ImagePicker from "expo-image-picker";
import { Alert, Linking } from "react-native";

export async function pickImage() {
  const current = await ImagePicker.getMediaLibraryPermissionsAsync();
  let status = current.status;
  if (status !== "granted") {
    const req = await ImagePicker.requestMediaLibraryPermissionsAsync();
    status = req.status;
  }
  if (status !== "granted") {
    Alert.alert("Permission needed", "Enable photo access in Settings", [
      { text: "Open Settings", onPress: () => Linking.openSettings() },
      { text: "Cancel", style: "cancel" },
    ]);
    return null;
  }
  const result = await ImagePicker.launchImageLibraryAsync({
    mediaTypes: ImagePicker.MediaTypeOptions.Images,
    quality: 0.8,
  });
  return result.canceled ? null : result.assets[0];
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Missing plist usage descriptions → App Store reject / crash on access.
* Requesting everything at launch → users deny all.
* Ignoring Android 13+ granular media permissions.

## 🔗 Related [#-related]

* [Expo/plugins.md](/docs/react-native/expo/plugins) — config plugins
* [Expo/config.md](/docs/react-native/expo/config) — app config
* [notification.md](/docs/react-native/notification) — notification permission
* [settings.md](/docs/react-native/settings) — open settings


---

# Picker (/docs/react-native/picker)



# Picker [#picker]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Pickers select from a list (date, time, dropdown). Core RN removed the old `Picker`; use `@react-native-picker/picker`, `@react-native-community/datetimepicker`, or Expo equivalents.

## 🔧 Core concepts [#-core-concepts]

* **`@react-native-picker/picker`** — `Picker` + `Picker.Item`.
* **Date/time** — community datetime picker; platform-native UI.
* **Expo** — `expo-date-picker` patterns via community modules; or JS UI pickers.
* **Controlled** — `selectedValue` + `onValueChange`.

## 💡 Examples [#-examples]

```tsx
import { useState } from "react";
import { Picker } from "@react-native-picker/picker";

export function FruitPicker() {
  const [fruit, setFruit] = useState("apple");
  return (
    <Picker selectedValue={fruit} onValueChange={(v) => setFruit(v)}>
      <Picker.Item label="Apple" value="apple" />
      <Picker.Item label="Banana" value="banana" />
      <Picker.Item label="Orange" value="orange" />
    </Picker>
  );
}
```

```tsx
import DateTimePicker from "@react-native-community/datetimepicker";
import { Platform } from "react-native";

export function Birthday({
  value,
  onChange,
}: {
  value: Date;
  onChange: (d: Date) => void;
}) {
  return (
    <DateTimePicker
      value={value}
      mode="date"
      display={Platform.OS === "ios" ? "spinner" : "default"}
      onChange={(_, date) => date && onChange(date)}
    />
  );
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Importing removed core `Picker` from `react-native`.
* Android date picker fires once and closes — manage `show` state.
* Styling differences: wrap platform-specific UI.

## 🔗 Related [#-related]

* [platform\_specific.md](/docs/react-native/platform-specific) — iOS vs Android UI
* [basic\_primitives.md](/docs/react-native/basic-primitives) — form layout
* [touchable.md](/docs/react-native/touchable) — open custom pickers
* [modal.md](/docs/react-native/modal) — picker in modal


---

# Platform-specific (/docs/react-native/platform-specific)



# Platform-specific [#platform-specific]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Branch behavior and files per OS with `Platform`, `.ios.tsx` / `.android.tsx` extensions, and platform select helpers. Keep shared logic in common modules.

## 🔧 Core concepts [#-core-concepts]

* **`Platform.OS`** — `"ios" | "android" | "web" | …`.
* **`Platform.select(\{ ios, android, default \})`**.
* **`Platform.Version`** — API level / iOS version.
* **Extensions** — `Button.ios.tsx`, `Button.android.tsx` resolved by Metro.
* **Expo** — `Platform` still applies; also check Constants for store client vs standalone.

## 💡 Examples [#-examples]

```tsx
import { Platform, StyleSheet, Text } from "react-native";

const styles = StyleSheet.create({
  shadow: Platform.select({
    ios: {
      shadowColor: "#000",
      shadowOpacity: 0.15,
      shadowRadius: 8,
      shadowOffset: { width: 0, height: 4 },
    },
    android: { elevation: 4 },
    default: {},
  }),
});

export function Hint() {
  return (
    <Text>
      {Platform.OS === "ios" ? "Swipe from left to go back" : "Use the back button"}
    </Text>
  );
}
```

```plaintext
components/
  Map.tsx          # shared types / re-export
  Map.ios.tsx
  Map.android.tsx
```

## ⚠️ Pitfalls [#️-pitfalls]

* Duplicating large components instead of small platform branches.
* Assuming `Platform.OS === "ios"` covers iPad idioms — check size classes too.
* Forgetting web when using React Native Web.

## 🔗 Related [#-related]

* [layout.md](/docs/react-native/layout) — shared layout
* [statusbar.md](/docs/react-native/statusbar) — bar styles differ
* [keyboard.md](/docs/react-native/keyboard) — avoiding behavior
* [Expo/config.md](/docs/react-native/expo/config) — platform config blocks


---

# Player (/docs/react-native/player)



# Player [#player]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Media playback (audio/video) uses libraries such as `expo-av`, `expo-audio` / `expo-video` (newer Expo SDK splits), `react-native-video`, or `react-native-track-player` for background audio.

## 🔧 Core concepts [#-core-concepts]

* **Load source** — local `require` or remote URI; handle buffering.
* **Controls** — play / pause / seek / rate; keep UI in sync with status callbacks.
* **Background** — audio session / foreground service; lock-screen controls need extra setup.
* **Lifecycle** — unload on unmount to free decoders.
* **Expo** — config plugins for background modes when needed.

## 💡 Examples [#-examples]

```tsx
import { useEffect, useRef } from "react";
import { Button } from "react-native";
import { Audio } from "expo-av";

export function SoundButton({ uri }: { uri: string }) {
  const soundRef = useRef<Audio.Sound | null>(null);

  useEffect(() => {
    return () => {
      soundRef.current?.unloadAsync();
    };
  }, []);

  async function toggle() {
    if (!soundRef.current) {
      const { sound } = await Audio.Sound.createAsync({ uri });
      soundRef.current = sound;
      await sound.playAsync();
      return;
    }
    const status = await soundRef.current.getStatusAsync();
    if (status.isLoaded && status.isPlaying) await soundRef.current.pauseAsync();
    else await soundRef.current.playAsync();
  }

  return <Button title="Play / Pause" onPress={toggle} />;
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Not unloading players → memory / decoder leaks.
* Autoplay policies and silent switch (iOS) — configure audio mode.
* Large remote files without progress / error UI.

## 🔗 Related [#-related]

* [permissions.md](/docs/react-native/permissions) — mic / media access
* [storage.md](/docs/react-native/storage) — cached files
* [Expo/plugins.md](/docs/react-native/expo/plugins) — native modules
* [networking.md](/docs/react-native/networking) — streaming URLs


---

# Pressable (/docs/react-native/pressable)



# Pressable [#pressable]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`Pressable` is the modern press handler—prefer it over `TouchableOpacity` / `TouchableHighlight`. Style from press state, configure hit slop, and set accessibility roles. See also [touchable.md](/docs/react-native/touchable) for legacy touchables.

## 🔧 Core concepts [#-core-concepts]

* **Events** — `onPress`, `onLongPress`, `onPressIn` / `Out`.
* **State style** — `style=\{(\{ pressed \}) => ...\}`.
* **`hitSlop`** — expand touch target.
* **`android_ripple`** — Material ripple.
* **`disabled`** — block interaction + a11y state.
* **Delay** — `delayLongPress`.

## 💡 Examples [#-examples]

```tsx
import { Pressable, Text, StyleSheet } from "react-native";

export function Button({
  label,
  onPress,
  disabled,
}: {
  label: string;
  onPress: () => void;
  disabled?: boolean;
}) {
  return (
    <Pressable
      accessibilityRole="button"
      accessibilityState={{ disabled: !!disabled }}
      disabled={disabled}
      hitSlop={8}
      android_ripple={{ color: "#ffffff55" }}
      onPress={onPress}
      style={({ pressed }) => [
        styles.btn,
        pressed && styles.pressed,
        disabled && styles.disabled,
      ]}
    >
      <Text style={styles.label}>{label}</Text>
    </Pressable>
  );
}

const styles = StyleSheet.create({
  btn: {
    backgroundColor: "#111",
    paddingVertical: 12,
    paddingHorizontal: 16,
    borderRadius: 8,
  },
  pressed: { opacity: 0.85 },
  disabled: { opacity: 0.4 },
  label: { color: "#fff", fontWeight: "600", textAlign: "center" },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Touch targets under \~44×44 pt.
* Nested Pressables competing for gestures.
* Using Touchable\* in new code without reason.
* Missing `accessibilityRole="button"`.

## 🔗 Related [#-related]

* [touchable.md](/docs/react-native/touchable) — legacy touchables
* [gesture.md](/docs/react-native/gesture) — advanced gestures
* [haptics.md](/docs/react-native/haptics) — feedback
* [accesebility.md](/docs/react-native/accesebility) — roles
* [animation.md](/docs/react-native/animation) — press animations


---

# React Native for Web (/docs/react-native/reactnativeforweb)



# React Native for Web [#react-native-for-web]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

**React Native for Web** (`react-native-web`) lets many React Native components and APIs run in the browser by mapping them to HTML/CSS. You keep `View` / `Text` / `StyleSheet` code and share UI across iOS, Android, and web — with platform-specific escapes when needed.

## 🔧 Core concepts [#-core-concepts]

| Idea               | Meaning                                               |
| ------------------ | ----------------------------------------------------- |
| `react-native-web` | Compatibility layer: RN primitives → DOM              |
| Alias              | Bundler maps `react-native` → `react-native-web`      |
| Shared UI          | One component tree for multiple targets               |
| Platform           | `Platform.OS === "web"` for web-only branches         |
| Expo web           | Expo can export/serve a web target with RN primitives |
| Limits             | Not every native module has a web equivalent          |

Typical stack: React + React DOM + `react-native-web` + Metro/Webpack/Vite/Expo.

## 💡 Examples [#-examples]

**Same component on native and web:**

```jsx
import { View, Text, StyleSheet, Platform } from "react-native";

export function Banner() {
  return (
    <View style={styles.box}>
      <Text style={styles.title}>Hello from {Platform.OS}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  box: {
    padding: 16,
    backgroundColor: "#e2e8f0",
    // web accepts extra CSS-like props via RN-web in many setups
    maxWidth: 480,
  },
  title: { fontSize: 18, fontWeight: "600" },
});
```

**Platform-specific file** (`Button.web.js` vs `Button.native.js`):

```jsx
// Button.web.js
export function Button({ label, onPress }) {
  return (
    <button type="button" onClick={onPress}>
      {label}
    </button>
  );
}
```

```jsx
// Button.native.js
import { Pressable, Text } from "react-native";

export function Button({ label, onPress }) {
  return (
    <Pressable onPress={onPress}>
      <Text>{label}</Text>
    </Pressable>
  );
}
```

**Expo web (concept):**

```shellscript
npx create-expo-app@latest MyApp
cd MyApp
npx expo start --web
```

**Webpack/Vite alias sketch (concept):**

```js
// resolve.alias (tool-dependent)
{
  "react-native$": "react-native-web"
}
```

**Safe branching:**

```jsx
import { Platform, Linking, Text } from "react-native";

async function openDocs() {
  const url = "https://necolas.github.io/react-native-web/";
  if (Platform.OS === "web") {
    window.open(url, "_blank", "noopener,noreferrer");
  } else {
    await Linking.openURL(url);
  }
}

// <Text onPress={openDocs}>Docs</Text>
```

## ⚠️ Pitfalls [#️-pitfalls]

* Native-only modules (camera, biometrics, some sensors) need web stubs or alternatives.
* Accessibility and SEO differ on web — you may need real landmarks/`<a href>` for marketing pages.
* Flexbox works, but browser scrolling, hover, and cursor need web-aware styling.
* Don’t assume pixel-perfect parity; test on a real browser early.
* Alias misconfiguration causes “Invalid hook call” or dual-React copies — keep a single `react` / `react-dom` version.

## 🔗 Related [#-related]

* [getting\_started.md](/docs/react-native/getting-started)
* [hello\_world.md](/docs/react-native/hello-world)
* [styling.md](/docs/react-native/styling)
* [linking.md](/docs/react-native/linking)
* [pressable.md](/docs/react-native/pressable)


---

# RefreshControl (/docs/react-native/refresh-control)



# RefreshControl [#refreshcontrol]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`RefreshControl` adds pull-to-refresh to `ScrollView` or `FlatList`. Drive it with controlled `refreshing` boolean and `onRefresh` that loads data then clears the flag.

## 🔧 Core concepts [#-core-concepts]

* **`refreshing`** — spinner visibility.
* **`onRefresh`** — start async reload.
* **Colors** — `tintColor` (iOS), `colors` (Android).
* **Progress view** — Android `progressViewOffset`.
* **Pair** — often with React Query `refetch`.

## 💡 Examples [#-examples]

```tsx
import { useCallback, useState } from "react";
import { FlatList, RefreshControl, Text } from "react-native";

export function Feed({
  items,
  reload,
}: {
  items: { id: string; title: string }[];
  reload: () => Promise<void>;
}) {
  const [refreshing, setRefreshing] = useState(false);

  const onRefresh = useCallback(async () => {
    setRefreshing(true);
    try {
      await reload();
    } finally {
      setRefreshing(false);
    }
  }, [reload]);

  return (
    <FlatList
      data={items}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => <Text>{item.title}</Text>}
      refreshControl={
        <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
      }
    />
  );
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Leaving `refreshing` true on error—use `try/finally`.
* Triggering refresh on mount unintentionally.
* Nested scrollables fighting the gesture.
* Not awaiting the fetch before clearing state.

## 🔗 Related [#-related]

* [flatlist.md](/docs/react-native/flatlist) — lists
* [scrollview.md](/docs/react-native/scrollview) — scroll
* [networking.md](/docs/react-native/networking) — fetch
* [request.md](/docs/react-native/request) — HTTP helpers
* [activity\_indicator.md](/docs/react-native/activity-indicator) — spinners


---

# Request (/docs/react-native/request)



# Request [#request]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Centralize HTTP requests: base URL, auth headers, error mapping, retries. Keep UI hooks thin; put transport in a small `api` / `request` module.

## 🔧 Core concepts [#-core-concepts]

* **Wrapper** — `request(path, options)` over `fetch`.
* **Interceptors** — inject tokens; refresh on 401.
* **Errors** — typed API errors with status + body.
* **Timeouts** — `AbortController` + `setTimeout`.
* **Caching** — React Query / SWR for GET dedupe.

## 💡 Examples [#-examples]

```ts
const BASE = "https://api.example.com";

export class ApiError extends Error {
  constructor(
    message: string,
    public status: number,
    public body: unknown,
  ) {
    super(message);
  }
}

export async function request<T>(
  path: string,
  init: RequestInit & { token?: string; timeoutMs?: number } = {},
): Promise<T> {
  const ctrl = new AbortController();
  const t = setTimeout(() => ctrl.abort(), init.timeoutMs ?? 15000);
  try {
    const res = await fetch(`${BASE}${path}`, {
      ...init,
      signal: ctrl.signal,
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
        ...(init.token ? { Authorization: `Bearer ${init.token}` } : {}),
        ...init.headers,
      },
    });
    const body = await res.json().catch(() => null);
    if (!res.ok) throw new ApiError("Request failed", res.status, body);
    return body as T;
  } finally {
    clearTimeout(t);
  }
}
```

```ts
export const getProfile = (token: string) =>
  request<{ name: string }>("/me", { token });
```

## ⚠️ Pitfalls [#️-pitfalls]

* Duplicating fetch logic in every screen.
* Swallowing errors without user feedback.
* Hardcoding secrets in the client — use backend for privileged calls.

## 🔗 Related [#-related]

* [networking.md](/docs/react-native/networking) — transport basics
* [storage.md](/docs/react-native/storage) — token persistence
* [settings.md](/docs/react-native/settings) — env / config flags
* [deeplinking.md](/docs/react-native/deeplinking) — post-auth routes


---

# Safe Area (/docs/react-native/safe-area)



# Safe Area [#safe-area]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Safe areas avoid notches, status bars, and home indicators. Use `react-native-safe-area-context` (`SafeAreaProvider`, `SafeAreaView`, `useSafeAreaInsets`)—the built-in `SafeAreaView` is limited (iOS-focused). Wrap the app once in a provider.

## 🔧 Core concepts [#-core-concepts]

* **`SafeAreaProvider`** — root wrapper.
* **`useSafeAreaInsets()`** — `\{ top, right, bottom, left \}`.
* **`SafeAreaView`** — applies padding edges.
* **`edges`** — choose which sides (`['top','bottom']`).
* **Headers** — native stack often handles top inset; don’t double-pad.

## 💡 Examples [#-examples]

```tsx
import {
  SafeAreaProvider,
  SafeAreaView,
  useSafeAreaInsets,
} from "react-native-safe-area-context";
import { View, Text, StyleSheet } from "react-native";

export function App() {
  return (
    <SafeAreaProvider>
      <Screen />
    </SafeAreaProvider>
  );
}

function Screen() {
  const insets = useSafeAreaInsets();
  return (
    <SafeAreaView style={styles.flex} edges={["top", "bottom"]}>
      <View style={[styles.fab, { bottom: insets.bottom + 16 }]}>
        <Text>FAB</Text>
      </View>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  flex: { flex: 1 },
  fab: {
    position: "absolute",
    right: 16,
    padding: 12,
    backgroundColor: "#111",
  },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Forgetting `SafeAreaProvider` → zero insets.
* Double-counting insets with header + screen padding.
* Using legacy RN `SafeAreaView` on Android expecting notch handling.
* Absolute tab bars covering content without bottom inset.

## 🔗 Related [#-related]

* [statusbar.md](/docs/react-native/statusbar) — status bar style
* [navigation.md](/docs/react-native/navigation) — headers
* [layout.md](/docs/react-native/layout) — flex
* [dimensions.md](/docs/react-native/dimensions) — screen size
* [styling.md](/docs/react-native/styling) — padding


---

# ScrollView (/docs/react-native/scrollview)



# ScrollView [#scrollview]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`ScrollView` scrolls a finite set of children. Use for short content (forms, static pages). For long or dynamic lists prefer `FlatList` / `SectionList`. Combine with `KeyboardAvoidingView` / `keyboardShouldPersistTaps` for forms.

## 🔧 Core concepts [#-core-concepts]

* **All children mount** — no virtualization.
* **Horizontal** — `horizontal` prop.
* **Refresh** — `refreshControl=\{<RefreshControl ... />\}`.
* **Paging** — `pagingEnabled`, `snapToInterval`.
* **Nested** — careful with lists; prefer one scroll parent.
* **Refs** — `scrollTo` / `scrollToEnd`.

## 💡 Examples [#-examples]

```tsx
import { ScrollView, Text, StyleSheet } from "react-native";

export function About() {
  return (
    <ScrollView
      contentContainerStyle={styles.content}
      keyboardShouldPersistTaps="handled"
    >
      <Text style={styles.title}>About</Text>
      <Text>Long copy…</Text>
    </ScrollView>
  );
}

const styles = StyleSheet.create({
  content: { padding: 16, paddingBottom: 48 },
  title: { fontSize: 22, marginBottom: 12 },
});
```

**Horizontal chips:**

```tsx
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
  {tags.map((t) => (
    <Chip key={t} label={t} />
  ))}
</ScrollView>
```

## ⚠️ Pitfalls [#️-pitfalls]

* Mapping hundreds of items into ScrollView → jank/memory.
* Nesting FlatList inside ScrollView (virtualization breaks).
* Forgetting bottom padding behind tab bars / home indicator.
* `keyboardShouldPersistTaps` default blocking taps while keyboard open.

## 🔗 Related [#-related]

* [flatlist.md](/docs/react-native/flatlist) — virtualized lists
* [keyboard.md](/docs/react-native/keyboard) — keyboard UX
* [refresh\_control.md](/docs/react-native/refresh-control) — pull to refresh
* [safe\_area.md](/docs/react-native/safe-area) — insets
* [layout.md](/docs/react-native/layout) — flex layout


---

# SectionList (/docs/react-native/sectionlist)



# SectionList [#sectionlist]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`SectionList` is a virtualized list of sections, each with a title and `data` array. Use for alphabetical contacts, grouped settings, or day-bucketed feeds. Same performance rules as `FlatList`.

## 🔧 Core concepts [#-core-concepts]

| Prop                          | Role                         |
| ----------------------------- | ---------------------------- |
| `sections`                    | `\{ title, data \}[]`        |
| `renderItem`                  | Row                          |
| `renderSectionHeader`         | Section title                |
| `keyExtractor`                | Item keys                    |
| `stickySectionHeadersEnabled` | Sticky headers (iOS default) |

Shape: `SectionListData<ItemT>`.

## 💡 Examples [#-examples]

```tsx
import { SectionList, Text, StyleSheet } from "react-native";

type Item = { id: string; name: string };
type Section = { title: string; data: Item[] };

export function Contacts({ sections }: { sections: Section[] }) {
  return (
    <SectionList
      sections={sections}
      keyExtractor={(item) => item.id}
      renderItem={({ item }) => <Text style={styles.row}>{item.name}</Text>}
      renderSectionHeader={({ section }) => (
        <Text style={styles.header}>{section.title}</Text>
      )}
    />
  );
}

const styles = StyleSheet.create({
  header: {
    fontWeight: "700",
    padding: 8,
    backgroundColor: "#f2f2f2",
  },
  row: { padding: 12 },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Empty `data` arrays still rendering awkward headers—filter sections.
* Unstable section object identities causing rerenders.
* Nesting inside ScrollView.
* Using SectionList for a single flat list—use FlatList.

## 🔗 Related [#-related]

* [flatlist.md](/docs/react-native/flatlist) — flat virtualization
* [scrollview.md](/docs/react-native/scrollview) — short content
* [refresh\_control.md](/docs/react-native/refresh-control) — pull to refresh
* [styling.md](/docs/react-native/styling) — headers
* [keys\_lists](/docs/react-native/../react/keys-lists) — keys


---

# Settings (/docs/react-native/settings)



# Settings [#settings]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

App settings span in-app preferences, opening the OS Settings page, and build-time config (`react-native-config`, Expo `extra` / env). Separate user prefs from secrets.

## 🔧 Core concepts [#-core-concepts]

* **In-app prefs** — theme, language, feature toggles → AsyncStorage / MMKV / SecureStore.
* **`Linking.openSettings()`** — send user to system app settings (permissions).
* **Build config** — `.env` via Expo (`EXPO_PUBLIC_*`) or native config libs.
* **Expo Constants** — `Constants.expoConfig?.extra` for non-secret config.

## 💡 Examples [#-examples]

```tsx
import { Linking, Pressable, Text } from "react-native";

export function OpenAppSettings() {
  return (
    <Pressable onPress={() => Linking.openSettings()} accessibilityRole="button">
      <Text>Open system settings</Text>
    </Pressable>
  );
}
```

```tsx
import Constants from "expo-constants";

const apiUrl =
  Constants.expoConfig?.extra?.apiUrl ?? "https://api.example.com";
```

```ts
// app.config.ts extra
export default {
  expo: {
    extra: {
      apiUrl: process.env.EXPO_PUBLIC_API_URL,
    },
  },
};
```

## ⚠️ Pitfalls [#️-pitfalls]

* Putting secrets in `EXPO_PUBLIC_*` or `extra` — they ship in the binary.
* Mixing permission recovery UI with preference screens without clear copy.
* Not migrating prefs when storage keys change.

## 🔗 Related [#-related]

* [storage.md](/docs/react-native/storage) — persistence
* [permissions.md](/docs/react-native/permissions) — settings deep link
* [Expo/config.md](/docs/react-native/expo/config) — app config
* [platform\_specific.md](/docs/react-native/platform-specific) — OS differences


---

# Share (/docs/react-native/share)



# Share [#share]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`Share` opens the platform share sheet for text/URLs (and files via community modules). Use it for invite links, exports, and content sharing.

## 🔧 Core concepts [#-core-concepts]

* **`Share.share(\{ message, url, title \})`** — core API.
* **Result** — `sharedAction` | `dismissedAction` (iOS mainly).
* **Files** — `expo-sharing` / `react-native-share` for images/PDFs.
* **Permissions** — writing to cache before sharing files.

## 💡 Examples [#-examples]

```tsx
import { Share, Pressable, Text, Platform } from "react-native";

export function ShareLink({ url }: { url: string }) {
  async function onShare() {
    try {
      await Share.share(
        Platform.OS === "ios"
          ? { url, message: "Check this out" }
          : { message: `Check this out ${url}` },
      );
    } catch {
      // user-facing error optional
    }
  }
  return (
    <Pressable onPress={onShare} accessibilityRole="button">
      <Text>Share</Text>
    </Pressable>
  );
}
```

```tsx
import * as Sharing from "expo-sharing";

async function shareFile(uri: string) {
  if (!(await Sharing.isAvailableAsync())) return;
  await Sharing.shareAsync(uri);
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Android often wants the URL inside `message`, not `url`.
* Assuming share succeeded when the sheet merely opened.
* Sharing huge files from remote URIs without downloading first.

## 🔗 Related [#-related]

* [clipboard.md](/docs/react-native/clipboard) — copy instead of share
* [storage.md](/docs/react-native/storage) — temp files
* [permissions.md](/docs/react-native/permissions) — media access
* [networking.md](/docs/react-native/networking) — download then share


---

# StatusBar (/docs/react-native/statusbar)



# StatusBar [#statusbar]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`StatusBar` controls the system status bar style (light/dark content) and visibility. Combine with **safe area** insets so content isn’t under the bar or notch.

## 🔧 Core concepts [#-core-concepts]

* **`barStyle`** — `"light-content"` | `"dark-content"`.
* **`backgroundColor`** — Android; iOS is typically transparent over the scene.
* **`translucent`** — Android draws under the bar.
* **Per-screen** — React Navigation `options=\{\{ statusBarStyle \}\}` or `<StatusBar />` in screen.
* **Expo** — `expo-status-bar` (`style="light"`).

## 💡 Examples [#-examples]

```tsx
import { StatusBar, View, Text, StyleSheet } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";

export function DarkHeader() {
  const insets = useSafeAreaInsets();
  return (
    <View style={[styles.header, { paddingTop: insets.top, backgroundColor: "#111" }]}>
      <StatusBar barStyle="light-content" />
      <Text style={styles.title}>Inbox</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  header: { paddingHorizontal: 16, paddingBottom: 12 },
  title: { color: "#fff", fontSize: 20, fontWeight: "600" },
});
```

```tsx
import { StatusBar } from "expo-status-bar";

<StatusBar style="dark" />;
```

## ⚠️ Pitfalls [#️-pitfalls]

* Setting bar style without matching background → unreadable icons.
* Ignoring safe area → content under notch / Dynamic Island.
* Multiple conflicting `StatusBar` mounts across stacked screens.

## 🔗 Related [#-related]

* [layout.md](/docs/react-native/layout) — padding / flex
* [dimensions.md](/docs/react-native/dimensions) — window metrics
* [platform\_specific.md](/docs/react-native/platform-specific) — Android vs iOS
* [transition.md](/docs/react-native/transition) — screen changes


---

# Storage (/docs/react-native/storage)



# Storage [#storage]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Persist data on device: **AsyncStorage** / **MMKV** for general prefs, **SecureStore** / Keychain for secrets, and the filesystem for files. Remember the store is per-install and can be cleared.

## 🔧 Core concepts [#-core-concepts]

* **AsyncStorage** — async key/value strings; fine for small prefs.
* **MMKV** — fast sync-ish storage (via JSI); great for app state.
* **SecureStore / Keychain** — tokens, not large blobs.
* **File system** — `expo-file-system` for downloads/cache.
* **Serialization** — `JSON.stringify` / `parse` with versioned schemas.

## 💡 Examples [#-examples]

```tsx
import AsyncStorage from "@react-native-async-storage/async-storage";

const KEY = "settings/v1";

export async function loadSettings<T>(fallback: T): Promise<T> {
  const raw = await AsyncStorage.getItem(KEY);
  if (!raw) return fallback;
  try {
    return JSON.parse(raw) as T;
  } catch {
    return fallback;
  }
}

export async function saveSettings<T>(value: T) {
  await AsyncStorage.setItem(KEY, JSON.stringify(value));
}
```

```tsx
import * as SecureStore from "expo-secure-store";

await SecureStore.setItemAsync("session", token);
const token = await SecureStore.getItemAsync("session");
```

## ⚠️ Pitfalls [#️-pitfalls]

* Storing secrets in AsyncStorage.
* Unbounded growth — no eviction strategy for caches.
* Assuming storage survives reinstall or OS backup policies for secure items.

## 🔗 Related [#-related]

* [settings.md](/docs/react-native/settings) — preferences UX
* [request.md](/docs/react-native/request) — auth tokens
* [clipboard.md](/docs/react-native/clipboard) — ephemeral data
* [Expo/config.md](/docs/react-native/expo/config) — Expo modules


---

# Styling (/docs/react-native/styling)



# Styling [#styling]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

RN styles use a subset of CSS via `StyleSheet.create` or inline objects. Layout is Flexbox by default (`flexDirection: 'column'`). No cascading selectors—compose style arrays. Prefer `StyleSheet` for identity and validation.

## 🔧 Core concepts [#-core-concepts]

| Topic       | Notes                                                     |
| ----------- | --------------------------------------------------------- |
| Flexbox     | `flex`, `justifyContent`, `alignItems`, `gap` (modern RN) |
| Units       | Density-independent numbers (dp), not `px` strings        |
| Platform    | `Platform.select` / `.ios.md` files                       |
| Composition | `style=\{[styles.base, cond && styles.active]\}`          |
| Text        | Limited font props; custom fonts need linking/Expo plugin |

Libraries: NativeWind, Restyle, Tamagui—optional.

## 💡 Examples [#-examples]

```tsx
import { Platform, StyleSheet, Text, View } from "react-native";

export function Card({ title }: { title: string }) {
  return (
    <View style={styles.card}>
      <Text style={styles.title}>{title}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  card: {
    padding: 16,
    borderRadius: 12,
    backgroundColor: "#fff",
    ...Platform.select({
      ios: {
        shadowColor: "#000",
        shadowOpacity: 0.1,
        shadowRadius: 8,
        shadowOffset: { width: 0, height: 2 },
      },
      android: { elevation: 3 },
    }),
  },
  title: {
    fontSize: 18,
    fontWeight: "600",
    color: "#111",
  },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Assuming web CSS (no inheritance for most text styles beyond Text parent quirks).
* Percentage heights without parent flex/height.
* Inline new style objects in hot list rows without need.
* Hardcoding colors everywhere—centralize tokens.

## 🔗 Related [#-related]

* [layout.md](/docs/react-native/layout) — flex patterns
* [platform\_specific.md](/docs/react-native/platform-specific) — Platform
* [dimensions.md](/docs/react-native/dimensions) — size
* [basic\_primitives.md](/docs/react-native/basic-primitives) — View/Text
* [safe\_area.md](/docs/react-native/safe-area) — insets


---

# TextInput (/docs/react-native/textinput)



# TextInput [#textinput]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`TextInput` is the core text entry component. Controlled via `value` + `onChangeText`. Tune keyboard (`keyboardType`, `autoCapitalize`, `secureTextEntry`), and handle focus with refs. Pair with labels for accessibility.

## 🔧 Core concepts [#-core-concepts]

| Prop                                | Role               |
| ----------------------------------- | ------------------ |
| `value` / `onChangeText`            | Controlled text    |
| `defaultValue`                      | Uncontrolled start |
| `placeholder`                       | Hint               |
| `secureTextEntry`                   | Password           |
| `keyboardType`                      | email/number/…     |
| `multiline` / `numberOfLines`       | Text area          |
| `returnKeyType` / `onSubmitEditing` | Keyboard action    |
| `editable`                          | Disable            |

Use `autoComplete` / `textContentType` for password managers.

## 💡 Examples [#-examples]

```tsx
import { useRef, useState } from "react";
import { TextInput, Pressable, Text, StyleSheet } from "react-native";

export function LoginFields() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const passwordRef = useRef<TextInput>(null);

  return (
    <>
      <Text nativeID="emailLabel">Email</Text>
      <TextInput
        style={styles.input}
        value={email}
        onChangeText={setEmail}
        keyboardType="email-address"
        autoCapitalize="none"
        autoComplete="email"
        accessibilityLabelledBy="emailLabel"
        returnKeyType="next"
        onSubmitEditing={() => passwordRef.current?.focus()}
      />
      <TextInput
        ref={passwordRef}
        style={styles.input}
        value={password}
        onChangeText={setPassword}
        secureTextEntry
        autoComplete="password"
        accessibilityLabel="Password"
      />
    </>
  );
}

const styles = StyleSheet.create({
  input: {
    borderWidth: 1,
    borderColor: "#ccc",
    borderRadius: 8,
    padding: 12,
    marginBottom: 12,
  },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Controlled input without updating `value` → can’t type.
* Wrapping in a scroll view without `keyboardShouldPersistTaps`.
* Tiny touch targets / missing labels.
* Android `underlineColorAndroid` surprises—set transparent if needed.

## 🔗 Related [#-related]

* [keyboard.md](/docs/react-native/keyboard) — avoid/cover
* [scrollview.md](/docs/react-native/scrollview) — forms
* [pressable.md](/docs/react-native/pressable) — submit buttons
* [accesebility.md](/docs/react-native/accesebility) — labels
* [touchable.md](/docs/react-native/touchable) — press handling


---

# Touchable (/docs/react-native/touchable)



# Touchable [#touchable]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Handle presses with &#x2A;*`Pressable`** (recommended), or legacy `TouchableOpacity` / `TouchableHighlight` / `TouchableWithoutFeedback`. Inside Gesture Handler navigators, prefer RNGH touchables.

## 🔧 Core concepts [#-core-concepts]

* **`Pressable`** — `onPress`, `onLongPress`, style as function of `\{ pressed \}`.
* **Hit slop** — expand touch target without changing layout.
* **Disabled** — `disabled` + a11y state.
* **Feedback** — opacity, ripple (`android_ripple`), haptic via Expo Haptics.
* **Legacy** — Touchable\* still work; migrate to Pressable when touching code.

## 💡 Examples [#-examples]

```tsx
import { Pressable, Text, StyleSheet } from "react-native";

export function PrimaryButton({
  label,
  onPress,
  disabled,
}: {
  label: string;
  onPress: () => void;
  disabled?: boolean;
}) {
  return (
    <Pressable
      onPress={onPress}
      disabled={disabled}
      hitSlop={8}
      accessibilityRole="button"
      accessibilityState={{ disabled: !!disabled }}
      android_ripple={{ color: "#ffffff55" }}
      style={({ pressed }) => [
        styles.btn,
        pressed && styles.pressed,
        disabled && styles.disabled,
      ]}
    >
      <Text style={styles.label}>{label}</Text>
    </Pressable>
  );
}

const styles = StyleSheet.create({
  btn: {
    backgroundColor: "#111",
    paddingVertical: 12,
    paddingHorizontal: 16,
    borderRadius: 8,
  },
  pressed: { opacity: 0.85 },
  disabled: { opacity: 0.4 },
  label: { color: "#fff", fontWeight: "600", textAlign: "center" },
});
```

## ⚠️ Pitfalls [#️-pitfalls]

* Touch targets smaller than \~44×44 pt.
* Wrapping `Text` alone without Pressable when you need a button role.
* Nested pressables stealing taps — flatten or use `pointerEvents`.

## 🔗 Related [#-related]

* [gesture.md](/docs/react-native/gesture) — advanced gestures
* [accesebility.md](/docs/react-native/accesebility) — roles / labels
* [basic\_primitives.md](/docs/react-native/basic-primitives) — Text / View
* [animation.md](/docs/react-native/animation) — press animations


---

# Transition (/docs/react-native/transition)



# Transition [#transition]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Transitions animate between UI states or screens. Use navigator transition configs, `Animated` / Reanimated shared element patterns, or simple mount/unmount fades.

## 🔧 Core concepts [#-core-concepts]

* **Stack transitions** — slide, fade, modal presentation (React Navigation / native stack).
* **LayoutAnimation** — animate flex layout changes after state updates.
* **Shared values** — Reanimated for interactive, interruptible transitions.
* **Presence** — delay unmount until exit animation finishes.
* **Native stack** — best performance; limited custom interpolation vs JS stack.

## 💡 Examples [#-examples]

```tsx
import { createNativeStackNavigator } from "@react-navigation/native-stack";

const Stack = createNativeStackNavigator();

export function RootStack() {
  return (
    <Stack.Navigator
      screenOptions={{
        animation: "slide_from_right",
        fullScreenGestureEnabled: true,
      }}
    >
      <Stack.Screen name="Home" component={Home} />
      <Stack.Screen
        name="Details"
        component={Details}
        options={{ animation: "fade_from_bottom", presentation: "modal" }}
      />
    </Stack.Navigator>
  );
}
```

```tsx
import { LayoutAnimation, Platform, UIManager, Pressable } from "react-native";

if (Platform.OS === "android" && UIManager.setLayoutAnimationEnabledExperimental) {
  UIManager.setLayoutAnimationEnabledExperimental(true);
}

function toggle(setOpen: (fn: (v: boolean) => boolean) => void) {
  LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
  setOpen((v) => !v);
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Heavy JS transitions dropping frames — prefer native stack / Reanimated.
* Animating during rapid navigation spam without cancellation.
* Forgetting Android LayoutAnimation experimental flag on older RN.

## 🔗 Related [#-related]

* [animation.md](/docs/react-native/animation) — Animated / Reanimated
* [drawer.md](/docs/react-native/drawer) — drawer motion
* [modal.md](/docs/react-native/modal) — modal presentation
* [gesture.md](/docs/react-native/gesture) — interactive pops


---

# Vibration (/docs/react-native/vibration)



# Vibration [#vibration]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

`Vibration` triggers the device vibrator for tactile feedback. Simple on Android/iOS; patterns are mainly Android. For richer feedback on iOS, prefer **Expo Haptics** / native haptics APIs.

## 🔧 Core concepts [#-core-concepts]

| API                          | Role                                    |
| ---------------------------- | --------------------------------------- |
| `Vibration.vibrate()`        | Default buzz                            |
| `Vibration.vibrate(ms)`      | Duration (Android)                      |
| `Vibration.vibrate(pattern)` | Android pattern `[wait, buzz, …]`       |
| `Vibration.cancel()`         | Stop                                    |
| iOS                          | Duration often ignored; pattern limited |

Permissions: generally none for basic vibrate; respect user settings.

## 💡 Examples [#-examples]

```tsx
import { Vibration, Pressable, Text, Platform } from "react-native";

export function BuzzButton() {
  return (
    <Pressable
      onPress={() => {
        if (Platform.OS === "android") {
          Vibration.vibrate([0, 50, 40, 50]);
        } else {
          Vibration.vibrate();
        }
      }}
    >
      <Text>Buzz</Text>
    </Pressable>
  );
}
```

## ⚠️ Pitfalls [#️-pitfalls]

* Overusing vibration → annoying / battery drain.
* Expecting Android patterns to feel identical on iOS.
* Using Vibration when Haptics impact/selection is more appropriate.
* Not cancelling long patterns on unmount.

## 🔗 Related [#-related]

* [haptics.md](/docs/react-native/haptics) — Expo/iOS-quality haptics
* [pressable.md](/docs/react-native/pressable) — press feedback
* [alert.md](/docs/react-native/alert) — confirmations
* [platform\_specific.md](/docs/react-native/platform-specific) — Platform
* [accesebility.md](/docs/react-native/accesebility) — reduce motion / feedback


---

# Widget (/docs/react-native/widget)



# Widget [#widget]

*React Native · Reference cheat sheet*

***

## 📋 Overview [#-overview]

Home-screen widgets are **native** (WidgetKit on iOS, App Widgets on Android). React Native doesn’t render them directly — share data via App Groups / a native module, or use libraries that bridge widget timelines.

## 🔧 Core concepts [#-core-concepts]

* **Native UI** — SwiftUI / RemoteViews; JS updates data, not the widget tree each frame.
* **Data bridge** — UserDefaults App Group, SharedPreferences, or a small native module.
* **Expo** — config plugins / custom native code (dev client or prebuild); limited Expo Go support.
* **Update cadence** — system-controlled refresh budgets; don’t expect real-time RN re-renders.
* **Deep link** — widget taps open the app via URL scheme.

## 💡 Examples [#-examples]

```tsx
// Conceptual: write shared state the native widget reads
import AsyncStorage from "@react-native-async-storage/async-storage";
// Prefer a native module that writes to App Group / SharedPreferences:
// await WidgetBridge.setData({ streak: 5 });

export async function syncWidgetPayload(streak: number) {
  await AsyncStorage.setItem("widget/streak", String(streak));
  // Native side: read key and reload timelines (WidgetCenter / updateAppWidget)
}
```

```swift
// iOS sketch — TimelineProvider reads App Group
// UserDefaults(suiteName: "group.com.example.app")?.integer(forKey: "streak")
```

## ⚠️ Pitfalls [#️-pitfalls]

* Expecting full RN components inside the widget — not supported.
* Over-refreshing timelines → OS throttles updates.
* Missing App Group / package entitlements in Expo config plugins.

## 🔗 Related [#-related]

* [deeplinking.md](/docs/react-native/deeplinking) — open app from widget
* [storage.md](/docs/react-native/storage) — shared data
* [Expo/plugins.md](/docs/react-native/expo/plugins) — native extensions
* [Expo/build.md](/docs/react-native/expo/build) — native builds

