# React Native — User Guide

React Native is Meta's open-source framework for building truly native mobile applications for iOS and Android using JavaScript and React. Rather than rendering web views, React Native translates your React components into real native platform widgets — delivering the performance and feel of a native app with the productivity of React's declarative UI model.

This guide covers everything you need to go from zero to a production-ready React Native app: installation, configuration, core concepts, common tasks, and troubleshooting for real-world issues.

> [!NOTE]
> This guide covers React Native **0.86.x** on the **New Architecture** (Fabric renderer, TurboModules, Codegen). The New Architecture is the default for all new projects. If you need details on internals, architecture decisions, or deployment infrastructure, see the [Admin Guide](/facebook/react-native/admin-guide/) (Admin section).

---

## Table of Contents

- [1. Quick Start](#1-quick-start)
- [2. Installation](#2-installation)
- [3. Configuration](#3-configuration)
- [4. Core Usage](#4-core-usage)
- [5. Common Tasks](#5-common-tasks)
- [6. Troubleshooting](#6-troubleshooting)
- [7. FAQ](#7-faq)

---

## 1. Quick Start

Get a new React Native app running on a simulator or device in under five minutes.

### 1.1 Prerequisites at a Glance

| Requirement | Version |
|---|---|
| Node.js | `^20.19.4 \|\| ^22.13.0 \|\| ^24.3.0 \|\| >= 25.0.0` |
| Ruby (iOS only) | >= 2.6.10 |
| Xcode (iOS) | Latest stable |
| Android Studio (Android) | Latest stable with SDK 35+ |

### 1.2 Create and Run Your First App

```bash
npx @react-native-community/cli@latest init MyFirstApp
cd MyFirstApp
```

Run on iOS:

```bash
npx react-native start
# In a new terminal:
npx react-native run-ios
```

Run on Android (ensure an emulator is running or a device is connected):

```bash
npx react-native start
# In a new terminal:
npx react-native run-android
```

Expected output from `npx react-native start`:

```
info Starting dev server on port 8081...

                        ▐▀▄       ▄▀▌
                        ▐ ▀▄▄▄▄▄▀ ▌
                        ▐         ▌
                        ▐         ▌
                        ▐    ▄    ▌
                        ▐   ▐ ▌   ▌
                        ▐   ▀ ▀   ▌

               Welcome to React Native 0.86
                 Dev server ready.
```

### 1.3 Edit Your App

Open `App.tsx` in your editor. Make a change, save, and watch it appear instantly on the device — Fast Refresh is enabled by default.

```tsx
import React from 'react';
import {SafeAreaView, Text, StyleSheet} from 'react-native';

function App(): React.JSX.Element {
  return (
    <SafeAreaView style={styles.container}>
      <Text style={styles.title}>Hello, React Native!</Text>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
  },
});

export default App;
```

> [!TIP]
> Shake your device (or press `Cmd+D` on iOS Simulator / `Cmd+M` on Android Emulator) to open the Dev Menu. From there you can toggle the inspector, reload the app, or open React Native DevTools.

---

## 2. Installation

### 2.1 System Requirements

#### 2.1.1 All Platforms

| Tool | Required Version | Purpose |
|---|---|---|
| Node.js | `^20.19.4 \|\| ^22.13.0 \|\| ^24.3.0 \|\| >= 25.0.0` | JavaScript runtime |
| npm / Yarn | Bundled with Node / latest | Package management |
| Watchman | Latest (recommended) | File watching for Fast Refresh |
| Git | Latest | Source control |

#### 2.1.2 iOS Development (macOS Only)

| Tool | Required Version | Purpose |
|---|---|---|
| macOS | Latest or previous major | Host OS for iOS builds |
| Xcode | Latest stable | iOS SDK, simulator, build tools |
| Xcode Command Line Tools | Matching Xcode | `xcode-select --install` |
| Ruby | >= 2.6.10 | CocoaPods dependency manager |
| CocoaPods | Latest | iOS native dependency management |

#### 2.1.3 Android Development

| Tool | Required Version | Purpose |
|---|---|---|
| Android Studio | Latest stable | Android SDK, emulator, build tools |
| Android SDK | API 35+ | Target platform |
| Android SDK Build-Tools | Latest | Compilation |
| Android NDK | Required for native modules | C++ compilation |
| Java Development Kit | JDK 17 | Gradle builds |

### 2.2 macOS Setup

#### 2.2.1 Install Homebrew Dependencies

```bash
brew install node watchman
```

Verify Node version:

```bash
node --version
# Expected: v22.x.x or v20.x.x (matching required range)
```

#### 2.2.2 Install Ruby and CocoaPods (iOS)

macOS ships with Ruby, but using a version manager is recommended:

```bash
brew install rbenv ruby-build
rbenv install 3.3.0
rbenv global 3.3.0

# Verify
ruby --version
# Expected: ruby 3.3.0 or higher

gem install cocoapods
```

#### 2.2.3 Install Xcode (iOS)

1. Install Xcode from the Mac App Store
2. Open Xcode and accept the license agreement
3. Install Command Line Tools:

```bash
xcode-select --install
```

4. Verify the installation:

```bash
xcodebuild -version
# Expected: Xcode 16.x, Build version ...
```

#### 2.2.4 Install Android Studio (Android)

1. Download Android Studio from https://developer.android.com/studio
2. During installation, ensure these are checked:
   - Android SDK
   - Android SDK Platform
   - Android Virtual Device
3. Open Android Studio > Settings > SDK Manager
4. Install SDK Platform for your target API level (35+)
5. Install NDK (Side by side) under SDK Tools tab

#### 2.2.5 Configure Environment Variables

Add to your `~/.zshrc` or `~/.bash_profile`:

```bash
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/platform-tools
```

Reload your shell:

```bash
source ~/.zshrc
```

### 2.3 Windows Setup (Android Only)

> [!IMPORTANT]
> iOS development requires macOS. On Windows, you can only build for Android. Use a Mac or a cloud-based Mac service for iOS builds.

#### 2.3.1 Install Node.js

Download the LTS installer from https://nodejs.org/ or use a version manager:

```powershell
# Using Chocolatey
choco install nodejs-lts

# Verify
node --version
```

#### 2.3.2 Install Android Studio

1. Download from https://developer.android.com/studio
2. During install, check: Android SDK, Android SDK Platform, Android Virtual Device
3. Install SDK Platform API 35+ from SDK Manager
4. Install NDK from SDK Tools tab

#### 2.3.3 Configure Environment Variables

Set the following system environment variables:

| Variable | Value |
|---|---|
| `ANDROID_HOME` | `C:\Users\<user>\AppData\Local\Android\Sdk` |
| Add to `Path` | `%ANDROID_HOME%\emulator` |
| Add to `Path` | `%ANDROID_HOME%\platform-tools` |

### 2.4 Linux Setup (Android Only)

```bash
# Install Node.js (using NodeSource)
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs

# Install Watchman
sudo apt-get install watchman

# Install JDK 17
sudo apt-get install openjdk-17-jdk
```

Then install Android Studio as described in section 2.3.2.

### 2.5 Creating a New Project

#### 2.5.1 Using npx (Recommended)

```bash
npx @react-native-community/cli@latest init MyProject
```

Expected output:

```
✔ Downloading template
✔ Copying template
✔ Processing template
✔ Installing dependencies
✔ Installing CocoaPods dependencies (iOS)

  Run instructions for iOS:
    npx react-native run-ios

  Run instructions for Android:
    npx react-native run-android
```

#### 2.5.2 With a Specific Version

```bash
npx @react-native-community/cli@latest init MyProject --version 0.86.0
```

#### 2.5.3 With a Custom Template

```bash
npx @react-native-community/cli@latest init MyProject --template react-native-template-typescript
```

### 2.6 Project Structure

After initialization, your project will have this structure:

```
MyProject/
├── __tests__/           # Jest test files
├── android/             # Android native project
│   ├── app/
│   │   ├── build.gradle
│   │   └── src/
│   ├── build.gradle
│   ├── gradle.properties
│   └── settings.gradle
├── ios/                 # iOS native project
│   ├── MyProject/
│   ├── Podfile
│   └── MyProject.xcworkspace
├── node_modules/
├── App.tsx              # Root component
├── app.json             # App configuration
├── babel.config.js      # Babel configuration
├── index.js             # App entry point
├── metro.config.js      # Metro bundler configuration
├── package.json
└── tsconfig.json        # TypeScript configuration
```

### 2.7 Verifying Your Setup

Run the built-in environment check:

```bash
npx react-native doctor
```

This checks for Node, Watchman, Xcode, CocoaPods, Android Studio, Android SDK, and JDK. Fix any issues it reports before proceeding.

---

## 3. Configuration

### 3.1 Metro Bundler Configuration

Metro is React Native's JavaScript bundler. The default configuration is provided by `@react-native/metro-config`.

#### 3.1.1 Default Configuration

Your project's `metro.config.js`:

```javascript
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');

const config = {};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);
```

The default configuration includes:

| Setting | Default Value | Purpose |
|---|---|---|
| Resolver fields | `['react-native', 'browser', 'main']` | Module resolution order |
| Platforms | `['android', 'ios']` | Supported target platforms |
| Inline requires | `true` | Performance optimization |
| Port | `8081` | Dev server port |

#### 3.1.2 Changing the Dev Server Port

Set the `RCT_METRO_PORT` environment variable:

```bash
RCT_METRO_PORT=8088 npx react-native start
```

Or configure it in `metro.config.js`:

```javascript
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');

const config = {
  server: {
    port: 8088,
  },
};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);
```

#### 3.1.3 Adding Asset Extensions

To support additional asset types beyond the defaults:

```javascript
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');

const defaultConfig = getDefaultConfig(__dirname);

const config = {
  resolver: {
    assetExts: [...defaultConfig.resolver.assetExts, 'obj', 'mtl', 'gltf'],
  },
};

module.exports = mergeConfig(defaultConfig, config);
```

#### 3.1.4 Adding Source Extensions

To support additional source file extensions:

```javascript
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');

const defaultConfig = getDefaultConfig(__dirname);

const config = {
  resolver: {
    sourceExts: [...defaultConfig.resolver.sourceExts, 'cjs', 'mjs'],
  },
};

module.exports = mergeConfig(defaultConfig, config);
```

#### 3.1.5 Configuring Module Aliases

```javascript
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const path = require('path');

const config = {
  resolver: {
    extraNodeModules: {
      '@app': path.resolve(__dirname, 'src'),
      '@components': path.resolve(__dirname, 'src/components'),
      '@utils': path.resolve(__dirname, 'src/utils'),
    },
  },
};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);
```

### 3.2 Babel Configuration

React Native uses `@react-native/babel-preset` which includes support for Flow stripping, class properties, async/await, optional chaining, nullish coalescing, and more.

#### 3.2.1 Default Configuration

Your `babel.config.js`:

```javascript
module.exports = {
  presets: ['module:@react-native/babel-preset'],
};
```

#### 3.2.2 Adding Plugins

```javascript
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    'react-native-reanimated/plugin', // Must be last
  ],
};
```

> [!WARNING]
> If you use `react-native-reanimated`, its Babel plugin **must** be listed last in the `plugins` array. Placing it elsewhere causes subtle runtime errors that are difficult to diagnose.

#### 3.2.3 Environment-Specific Configuration

```javascript
module.exports = (api) => {
  const isProd = api.env('production');

  return {
    presets: ['module:@react-native/babel-preset'],
    plugins: [
      isProd && 'transform-remove-console',
    ].filter(Boolean),
  };
};
```

### 3.3 TypeScript Configuration

Default `tsconfig.json`:

```json
{
  "extends": "@react-native/typescript-config/tsconfig.json",
  "compilerOptions": {
    "strict": true
  }
}
```

#### 3.3.1 Path Aliases with TypeScript

If you configure Metro module aliases (section 3.1.5), mirror them in `tsconfig.json`:

```json
{
  "extends": "@react-native/typescript-config/tsconfig.json",
  "compilerOptions": {
    "strict": true,
    "baseUrl": ".",
    "paths": {
      "@app/*": ["src/*"],
      "@components/*": ["src/components/*"],
      "@utils/*": ["src/utils/*"]
    }
  }
}
```

### 3.4 ESLint Configuration

React Native provides `@react-native/eslint-config` and `@react-native/eslint-plugin` for code quality.

#### 3.4.1 Default Setup

Your `.eslintrc.js`:

```javascript
module.exports = {
  root: true,
  extends: '@react-native',
};
```

This extends `@react-native/eslint-config`, which bundles rules for React, React Native, Jest, Flow/TypeScript, and Prettier.

#### 3.4.2 Adding Custom Rules

```javascript
module.exports = {
  root: true,
  extends: '@react-native',
  rules: {
    'no-console': 'warn',
    'react-native/no-inline-styles': 'warn',
    'react/no-unstable-nested-components': 'error',
  },
};
```

### 3.5 Jest Configuration

React Native uses `@react-native/jest-preset` for testing.

#### 3.5.1 Default Setup

In your `package.json`:

```json
{
  "jest": {
    "preset": "react-native"
  }
}
```

Or in a standalone `jest.config.js`:

```javascript
module.exports = {
  preset: 'react-native',
  setupFilesAfterSetup: ['./jest.setup.js'],
  transformIgnorePatterns: [
    'node_modules/(?!(react-native|@react-native|@react-navigation)/)',
  ],
};
```

#### 3.5.2 Module Name Mapping

If you use path aliases, configure Jest to resolve them:

```javascript
module.exports = {
  preset: 'react-native',
  moduleNameMapper: {
    '^@app/(.*)$': '<rootDir>/src/$1',
    '^@components/(.*)$': '<rootDir>/src/components/$1',
    '^@utils/(.*)$': '<rootDir>/src/utils/$1',
  },
};
```

### 3.6 Prettier Configuration

React Native uses these Prettier settings internally:

```json
{
  "arrowParens": "avoid",
  "singleQuote": true,
  "trailingComma": "all"
}
```

Create a `.prettierrc` in your project root with these or your preferred settings to maintain consistent formatting.

### 3.7 Android Configuration

#### 3.7.1 Gradle Plugin

React Native's Gradle plugin is applied in your Android project. The key plugins are:

- `com.facebook.react` — applied to your `app/build.gradle`
- `com.facebook.react.rootproject` — applied to the root `build.gradle`

#### 3.7.2 Gradle Properties

Key properties in `android/gradle.properties`:

```properties
# Enable the New Architecture (default: true in 0.86)
newArchEnabled=true

# Enable Hermes JS engine (default: true)
hermesEnabled=true

# Configure build variants
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
```

#### 3.7.3 App-Level build.gradle

```groovy
apply plugin: "com.facebook.react"

react {
    // Configures bundling for release builds
    // entryFile = file("index.js")
    // bundleCommand = "bundle"
}

android {
    namespace "com.myproject"
    compileSdk 35
    defaultConfig {
        applicationId "com.myproject"
        minSdk 24
        targetSdk 35
        versionCode 1
        versionName "1.0"
    }
}
```

### 3.8 iOS Configuration

#### 3.8.1 Podfile

The iOS `Podfile` manages native dependencies via CocoaPods:

```ruby
platform :ios, '15.1'

target 'MyProject' do
  config = use_native_modules!

  use_react_native!(
    :path => config[:reactNativePath],
    :hermes_enabled => true,
    :fabric_enabled => true,
  )

  post_install do |installer|
    react_native_post_install(installer)
  end
end
```

#### 3.8.2 Installing iOS Dependencies

```bash
cd ios
bundle install     # Install Ruby gems (if using Bundler)
pod install        # Install CocoaPods dependencies
cd ..
```

Expected output:

```
Analyzing dependencies
Downloading dependencies
Installing React-Core (0.86.0)
Installing hermes-engine (0.86.0)
...
Pod installation complete!
```

### 3.9 App Configuration (app.json)

The `app.json` file provides basic app metadata:

```json
{
  "name": "MyProject",
  "displayName": "My Project"
}
```

This is read by `index.js` to register the app:

```javascript
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';

AppRegistry.registerComponent(appName, () => App);
```

---

## 4. Core Usage

### 4.1 Components

React Native provides a set of core components that map directly to native platform views.

#### 4.1.1 Basic Components

| Component | Purpose | Native Equivalent |
|---|---|---|
| `View` | Container, layout | `UIView` (iOS), `ViewGroup` (Android) |
| `Text` | Display text | `UILabel` (iOS), `TextView` (Android) |
| `Image` | Display images | `UIImageView` (iOS), `ImageView` (Android) |
| `TextInput` | Text entry | `UITextField` (iOS), `EditText` (Android) |
| `ScrollView` | Scrollable container | `UIScrollView` (iOS), `ScrollView` (Android) |
| `Button` | Basic button | Native button |

```tsx
import React from 'react';
import {View, Text, Image, TextInput, Button, ScrollView} from 'react-native';

function BasicComponents(): React.JSX.Element {
  return (
    <ScrollView>
      <View style={{padding: 20}}>
        <Text>Hello, world!</Text>
        <Image
          source={{uri: 'https://reactnative.dev/img/tiny_logo.png'}}
          style={{width: 50, height: 50}}
        />
        <TextInput placeholder="Type here..." />
        <Button title="Press Me" onPress={() => console.log('Pressed!')} />
      </View>
    </ScrollView>
  );
}
```

#### 4.1.2 Layout with View and Flexbox

React Native uses Flexbox for layout. The default `flexDirection` is `column` (unlike web CSS which defaults to `row`).

```tsx
import React from 'react';
import {View, Text, StyleSheet} from 'react-native';

function FlexboxExample(): React.JSX.Element {
  return (
    <View style={styles.container}>
      <View style={styles.row}>
        <View style={[styles.box, {backgroundColor: '#e74c3c'}]}>
          <Text style={styles.label}>1</Text>
        </View>
        <View style={[styles.box, {backgroundColor: '#3498db'}]}>
          <Text style={styles.label}>2</Text>
        </View>
        <View style={[styles.box, {backgroundColor: '#2ecc71'}]}>
          <Text style={styles.label}>3</Text>
        </View>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    padding: 20,
  },
  row: {
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  box: {
    width: 80,
    height: 80,
    justifyContent: 'center',
    alignItems: 'center',
    borderRadius: 8,
  },
  label: {
    color: 'white',
    fontSize: 18,
    fontWeight: 'bold',
  },
});
```

Key Flexbox properties:

| Property | Values | Default |
|---|---|---|
| `flexDirection` | `column`, `row`, `column-reverse`, `row-reverse` | `column` |
| `justifyContent` | `flex-start`, `flex-end`, `center`, `space-between`, `space-around`, `space-evenly` | `flex-start` |
| `alignItems` | `flex-start`, `flex-end`, `center`, `stretch`, `baseline` | `stretch` |
| `flex` | Number | — |
| `flexWrap` | `wrap`, `nowrap` | `nowrap` |
| `gap` | Number | — |
| `rowGap` | Number | — |
| `columnGap` | Number | — |

#### 4.1.3 Text and Typography

```tsx
import React from 'react';
import {Text, StyleSheet} from 'react-native';

function Typography(): React.JSX.Element {
  return (
    <>
      <Text style={styles.heading}>Heading</Text>
      <Text style={styles.body}>
        Body text with <Text style={styles.bold}>bold</Text> and{' '}
        <Text style={styles.italic}>italic</Text> spans.
      </Text>
      <Text style={styles.link} onPress={() => console.log('Tapped!')}>
        Tappable text
      </Text>
      <Text numberOfLines={2} ellipsizeMode="tail">
        This is a very long paragraph that will be truncated after two lines
        because we set numberOfLines to 2 and ellipsizeMode to tail so it
        shows an ellipsis at the end.
      </Text>
    </>
  );
}

const styles = StyleSheet.create({
  heading: {
    fontSize: 28,
    fontWeight: 'bold',
    marginBottom: 8,
  },
  body: {
    fontSize: 16,
    lineHeight: 24,
    color: '#333',
  },
  bold: {
    fontWeight: 'bold',
  },
  italic: {
    fontStyle: 'italic',
  },
  link: {
    color: '#3498db',
    textDecorationLine: 'underline',
  },
});
```

#### 4.1.4 Images

```tsx
import React from 'react';
import {Image, ImageBackground, StyleSheet, Text, View} from 'react-native';

function ImageExamples(): React.JSX.Element {
  return (
    <View>
      {/* Local image (require) */}
      <Image source={require('./assets/logo.png')} style={styles.localImage} />

      {/* Remote image (must specify dimensions) */}
      <Image
        source={{uri: 'https://example.com/photo.jpg'}}
        style={styles.remoteImage}
        resizeMode="cover"
      />

      {/* Background image */}
      <ImageBackground
        source={require('./assets/background.png')}
        style={styles.background}>
        <Text style={styles.overlayText}>Overlay text</Text>
      </ImageBackground>
    </View>
  );
}

const styles = StyleSheet.create({
  localImage: {
    width: 100,
    height: 100,
  },
  remoteImage: {
    width: 200,
    height: 150,
    borderRadius: 8,
  },
  background: {
    width: '100%',
    height: 200,
    justifyContent: 'center',
    alignItems: 'center',
  },
  overlayText: {
    color: 'white',
    fontSize: 24,
    fontWeight: 'bold',
  },
});
```

Image `resizeMode` options:

| Mode | Behavior |
|---|---|
| `cover` | Scale to fill, may crop |
| `contain` | Scale to fit, may letterbox |
| `stretch` | Stretch to fill exactly |
| `repeat` | Tile the image (iOS only) |
| `center` | Center without scaling |

#### 4.1.5 TextInput

```tsx
import React, {useState} from 'react';
import {TextInput, View, Text, StyleSheet} from 'react-native';

function FormExample(): React.JSX.Element {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [bio, setBio] = useState('');

  return (
    <View style={styles.form}>
      <Text style={styles.label}>Name</Text>
      <TextInput
        style={styles.input}
        value={name}
        onChangeText={setName}
        placeholder="Your name"
        autoCapitalize="words"
        returnKeyType="next"
      />

      <Text style={styles.label}>Email</Text>
      <TextInput
        style={styles.input}
        value={email}
        onChangeText={setEmail}
        placeholder="[email removed]"
        keyboardType="email-address"
        autoCapitalize="none"
        autoCorrect={false}
        returnKeyType="next"
      />

      <Text style={styles.label}>Bio</Text>
      <TextInput
        style={[styles.input, styles.multiline]}
        value={bio}
        onChangeText={setBio}
        placeholder="Tell us about yourself..."
        multiline
        numberOfLines={4}
        textAlignVertical="top"
      />
    </View>
  );
}

const styles = StyleSheet.create({
  form: {
    padding: 20,
  },
  label: {
    fontSize: 14,
    fontWeight: '600',
    marginBottom: 4,
    color: '#333',
  },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 8,
    padding: 12,
    marginBottom: 16,
    fontSize: 16,
  },
  multiline: {
    height: 100,
  },
});
```

Keyboard types available via `keyboardType`:

| Value | Use Case |
|---|---|
| `default` | Standard text |
| `email-address` | Email input |
| `numeric` | Numbers only |
| `phone-pad` | Phone number |
| `decimal-pad` | Decimal numbers |
| `number-pad` | Integer numbers |
| `url` | URL input |

### 4.2 Styling

#### 4.2.1 StyleSheet API

Always use `StyleSheet.create()` for performance — it validates styles at creation time and creates optimized references:

```tsx
import {StyleSheet} from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    padding: 16,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#1a1a1a',
    marginBottom: 12,
  },
});
```

#### 4.2.2 Combining Styles

```tsx
// Array syntax — later styles override earlier ones
<View style={[styles.base, styles.active]} />

// Conditional styles
<View style={[styles.base, isActive && styles.active]} />

// Inline overrides
<View style={[styles.base, {marginTop: 10}]} />
```

#### 4.2.3 Platform-Specific Styles

```tsx
import {Platform, StyleSheet} from 'react-native';

const styles = StyleSheet.create({
  shadow: {
    ...Platform.select({
      ios: {
        shadowColor: '#000',
        shadowOffset: {width: 0, height: 2},
        shadowOpacity: 0.25,
        shadowRadius: 4,
      },
      android: {
        elevation: 5,
      },
    }),
  },
});
```

#### 4.2.4 Common Style Properties

React Native styles are a subset of CSS, written in camelCase. Key differences from web CSS:

| Category | Properties |
|---|---|
| Layout | `flex`, `flexDirection`, `justifyContent`, `alignItems`, `alignSelf`, `position`, `top`, `left`, `right`, `bottom`, `width`, `height`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `margin*`, `padding*`, `gap` |
| Visual | `backgroundColor`, `opacity`, `borderWidth`, `borderColor`, `borderRadius`, `borderStyle` |
| Text | `color`, `fontSize`, `fontWeight`, `fontStyle`, `fontFamily`, `lineHeight`, `textAlign`, `textDecorationLine`, `textTransform`, `letterSpacing` |
| Shadow (iOS) | `shadowColor`, `shadowOffset`, `shadowOpacity`, `shadowRadius` |
| Shadow (Android) | `elevation` |
| Transform | `transform: [{rotate: '45deg'}, {scale: 1.5}]` |

> [!NOTE]
> All dimensions in React Native are unitless and represent density-independent pixels (dp). There is no `px`, `em`, `rem`, or `%` unit (except for percentage strings like `'50%'` for width/height). This ensures consistent sizing across different screen densities.

### 4.3 Lists and Scrolling

#### 4.3.1 FlatList — Virtualized List

`FlatList` is the primary component for rendering long, scrollable lists. It only renders items currently visible on screen, making it efficient for large datasets.

```tsx
import React from 'react';
import {FlatList, Text, View, StyleSheet} from 'react-native';

interface Item {
  id: string;
  title: string;
}

const DATA: Item[] = Array.from({length: 1000}, (_, i) => ({
  id: String(i),
  title: `Item ${i + 1}`,
}));

function ListExample(): React.JSX.Element {
  const renderItem = ({item}: {item: Item}) => (
    <View style={styles.item}>
      <Text style={styles.itemText}>{item.title}</Text>
    </View>
  );

  return (
    <FlatList
      data={DATA}
      renderItem={renderItem}
      keyExtractor={item => item.id}
      ItemSeparatorComponent={() => <View style={styles.separator} />}
      ListHeaderComponent={() => (
        <Text style={styles.header}>All Items</Text>
      )}
      ListEmptyComponent={() => (
        <Text style={styles.empty}>No items found</Text>
      )}
    />
  );
}

const styles = StyleSheet.create({
  item: {
    padding: 16,
    backgroundColor: '#fff',
  },
  itemText: {
    fontSize: 16,
  },
  separator: {
    height: 1,
    backgroundColor: '#eee',
  },
  header: {
    fontSize: 20,
    fontWeight: 'bold',
    padding: 16,
  },
  empty: {
    padding: 20,
    textAlign: 'center',
    color: '#999',
  },
});
```

#### 4.3.2 SectionList — Grouped Data

```tsx
import React from 'react';
import {SectionList, Text, View, StyleSheet} from 'react-native';

const SECTIONS = [
  {
    title: 'Fruits',
    data: ['Apple', 'Banana', 'Cherry', 'Date'],
  },
  {
    title: 'Vegetables',
    data: ['Artichoke', 'Broccoli', 'Carrot', 'Daikon'],
  },
];

function SectionListExample(): React.JSX.Element {
  return (
    <SectionList
      sections={SECTIONS}
      keyExtractor={(item, index) => item + index}
      renderItem={({item}) => (
        <View style={styles.item}>
          <Text>{item}</Text>
        </View>
      )}
      renderSectionHeader={({section: {title}}) => (
        <View style={styles.sectionHeader}>
          <Text style={styles.sectionTitle}>{title}</Text>
        </View>
      )}
      stickySectionHeadersEnabled
    />
  );
}

const styles = StyleSheet.create({
  item: {
    padding: 16,
    backgroundColor: '#fff',
  },
  sectionHeader: {
    padding: 12,
    backgroundColor: '#f5f5f5',
  },
  sectionTitle: {
    fontSize: 16,
    fontWeight: 'bold',
  },
});
```

#### 4.3.3 Pull-to-Refresh

```tsx
import React, {useState, useCallback} from 'react';
import {FlatList, RefreshControl} from 'react-native';

function RefreshableList(): React.JSX.Element {
  const [refreshing, setRefreshing] = useState(false);
  const [data, setData] = useState(initialData);

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

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={item => item.id}
      refreshControl={
        <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
      }
    />
  );
}
```

#### 4.3.4 Infinite Scroll / Pagination

```tsx
function PaginatedList(): React.JSX.Element {
  const [data, setData] = useState<Item[]>([]);
  const [page, setPage] = useState(1);
  const [loading, setLoading] = useState(false);

  const loadMore = useCallback(async () => {
    if (loading) return;
    setLoading(true);
    const newItems = await fetchPage(page + 1);
    setData(prev => [...prev, ...newItems]);
    setPage(prev => prev + 1);
    setLoading(false);
  }, [page, loading]);

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={item => item.id}
      onEndReached={loadMore}
      onEndReachedThreshold={0.5}
      ListFooterComponent={loading ? <ActivityIndicator /> : null}
    />
  );
}
```

### 4.4 Handling User Input

#### 4.4.1 Touchables and Pressable

```tsx
import React from 'react';
import {
  Pressable,
  TouchableOpacity,
  TouchableHighlight,
  Text,
  StyleSheet,
} from 'react-native';

function ButtonExamples(): React.JSX.Element {
  return (
    <>
      {/* Pressable — most flexible, recommended */}
      <Pressable
        style={({pressed}) => [
          styles.button,
          pressed && styles.buttonPressed,
        ]}
        onPress={() => console.log('Pressed')}
        onLongPress={() => console.log('Long pressed')}
        hitSlop={10}>
        <Text style={styles.buttonText}>Pressable</Text>
      </Pressable>

      {/* TouchableOpacity — fades on press */}
      <TouchableOpacity
        style={styles.button}
        activeOpacity={0.7}
        onPress={() => console.log('Pressed')}>
        <Text style={styles.buttonText}>TouchableOpacity</Text>
      </TouchableOpacity>

      {/* TouchableHighlight — highlights on press */}
      <TouchableHighlight
        style={styles.button}
        underlayColor="#ddd"
        onPress={() => console.log('Pressed')}>
        <Text style={styles.buttonText}>TouchableHighlight</Text>
      </TouchableHighlight>
    </>
  );
}

const styles = StyleSheet.create({
  button: {
    backgroundColor: '#3498db',
    paddingVertical: 12,
    paddingHorizontal: 24,
    borderRadius: 8,
    marginBottom: 12,
  },
  buttonPressed: {
    backgroundColor: '#2980b9',
    transform: [{scale: 0.98}],
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '600',
    textAlign: 'center',
  },
});
```

#### 4.4.2 Gesture Handling

```tsx
import React from 'react';
import {View, PanResponder, Animated} from 'react-native';

function DraggableBox(): React.JSX.Element {
  const pan = React.useRef(new Animated.ValueXY()).current;

  const panResponder = React.useRef(
    PanResponder.create({
      onMoveShouldSetPanResponder: () => true,
      onPanResponderMove: Animated.event(
        [null, {dx: pan.x, dy: pan.y}],
        {useNativeDriver: false},
      ),
      onPanResponderRelease: () => {
        Animated.spring(pan, {
          toValue: {x: 0, y: 0},
          useNativeDriver: true,
        }).start();
      },
    }),
  ).current;

  return (
    <Animated.View
      style={[
        {
          width: 100,
          height: 100,
          backgroundColor: '#3498db',
          borderRadius: 8,
          transform: [{translateX: pan.x}, {translateY: pan.y}],
        },
      ]}
      {...panResponder.panHandlers}
    />
  );
}
```

### 4.5 Navigation

React Native does not include a built-in navigation system. The community-standard library is React Navigation (`@react-navigation`).

#### 4.5.1 Installing React Navigation

```bash
npm install @react-navigation/native @react-navigation/native-stack

# Required peer dependencies
npm install react-native-screens react-native-safe-area-context
```

For iOS, install pods:

```bash
cd ios && pod install && cd ..
```

#### 4.5.2 Stack Navigation

```tsx
import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import {Button, Text, View} from 'react-native';

type RootStackParamList = {
  Home: undefined;
  Details: {itemId: number};
};

const Stack = createNativeStackNavigator<RootStackParamList>();

function HomeScreen({navigation}: any): React.JSX.Element {
  return (
    <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text>Home Screen</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Details', {itemId: 42})}
      />
    </View>
  );
}

function DetailsScreen({route}: any): React.JSX.Element {
  const {itemId} = route.params;
  return (
    <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text>Details for item {itemId}</Text>
    </View>
  );
}

function App(): React.JSX.Element {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;
```

#### 4.5.3 Tab Navigation

```bash
npm install @react-navigation/bottom-tabs
```

```tsx
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';

const Tab = createBottomTabNavigator();

function App(): React.JSX.Element {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
        <Tab.Screen name="Profile" component={ProfileScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}
```

#### 4.5.4 Drawer Navigation

```bash
npm install @react-navigation/drawer react-native-gesture-handler react-native-reanimated
```

```tsx
import {createDrawerNavigator} from '@react-navigation/drawer';

const Drawer = createDrawerNavigator();

function App(): React.JSX.Element {
  return (
    <NavigationContainer>
      <Drawer.Navigator>
        <Drawer.Screen name="Home" component={HomeScreen} />
        <Drawer.Screen name="Settings" component={SettingsScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}
```

### 4.6 Networking

#### 4.6.1 Fetch API

React Native includes the standard `fetch` API:

```tsx
async function fetchUsers() {
  try {
    const response = await fetch('https://api.example.com/users');
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Fetch failed:', error);
    throw error;
  }
}
```

#### 4.6.2 POST Requests

```tsx
async function createUser(name: string, email: string) {
  const response = await fetch('https://api.example.com/users', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'Bearer YOUR_TOKEN',
    },
    body: JSON.stringify({name, email}),
  });
  return response.json();
}
```

#### 4.6.3 Using Data in Components

```tsx
import React, {useState, useEffect} from 'react';
import {FlatList, Text, View, ActivityIndicator} from 'react-native';

interface User {
  id: number;
  name: string;
}

function UserList(): React.JSX.Element {
  const [users, setUsers] = useState<User[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users')
      .then(res => res.json())
      .then(data => {
        setUsers(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, []);

  if (loading) return <ActivityIndicator size="large" />;
  if (error) return <Text>Error: {error}</Text>;

  return (
    <FlatList
      data={users}
      keyExtractor={item => String(item.id)}
      renderItem={({item}) => (
        <View style={{padding: 16}}>
          <Text>{item.name}</Text>
        </View>
      )}
    />
  );
}
```

#### 4.6.4 WebSocket

```tsx
const ws = new WebSocket('wss://echo.websocket.org');

ws.onopen = () => {
  ws.send('Hello from React Native!');
};

ws.onmessage = (event) => {
  console.log('Received:', event.data);
};

ws.onerror = (error) => {
  console.error('WebSocket error:', error);
};

ws.onclose = () => {
  console.log('WebSocket closed');
};
```

### 4.7 State Management

#### 4.7.1 useState

```tsx
import React, {useState} from 'react';
import {View, Text, Button} from 'react-native';

function Counter(): React.JSX.Element {
  const [count, setCount] = useState(0);

  return (
    <View>
      <Text>Count: {count}</Text>
      <Button title="Increment" onPress={() => setCount(c => c + 1)} />
      <Button title="Decrement" onPress={() => setCount(c => c - 1)} />
      <Button title="Reset" onPress={() => setCount(0)} />
    </View>
  );
}
```

#### 4.7.2 useReducer

```tsx
import React, {useReducer} from 'react';
import {View, Text, Button} from 'react-native';

type State = {count: number};
type Action = {type: 'increment'} | {type: 'decrement'} | {type: 'reset'};

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    case 'reset':
      return {count: 0};
  }
}

function Counter(): React.JSX.Element {
  const [state, dispatch] = useReducer(reducer, {count: 0});

  return (
    <View>
      <Text>Count: {state.count}</Text>
      <Button title="+" onPress={() => dispatch({type: 'increment'})} />
      <Button title="-" onPress={() => dispatch({type: 'decrement'})} />
      <Button title="Reset" onPress={() => dispatch({type: 'reset'})} />
    </View>
  );
}
```

#### 4.7.3 Context API

```tsx
import React, {createContext, useContext, useState} from 'react';

interface ThemeContextType {
  isDark: boolean;
  toggle: () => void;
}

const ThemeContext = createContext<ThemeContextType>({
  isDark: false,
  toggle: () => {},
});

function ThemeProvider({children}: {children: React.ReactNode}) {
  const [isDark, setIsDark] = useState(false);
  const toggle = () => setIsDark(prev => !prev);

  return (
    <ThemeContext.Provider value={{isDark, toggle}}>
      {children}
    </ThemeContext.Provider>
  );
}

function useTheme() {
  return useContext(ThemeContext);
}

// Usage in a component
function ThemedScreen(): React.JSX.Element {
  const {isDark, toggle} = useTheme();

  return (
    <View style={{backgroundColor: isDark ? '#333' : '#fff', flex: 1}}>
      <Text style={{color: isDark ? '#fff' : '#333'}}>
        Current theme: {isDark ? 'Dark' : 'Light'}
      </Text>
      <Button title="Toggle Theme" onPress={toggle} />
    </View>
  );
}
```

### 4.8 Animations

#### 4.8.1 Animated API

```tsx
import React, {useRef, useEffect} from 'react';
import {Animated, View, Text, StyleSheet} from 'react-native';

function FadeInView({children}: {children: React.ReactNode}): React.JSX.Element {
  const fadeAnim = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.timing(fadeAnim, {
      toValue: 1,
      duration: 800,
      useNativeDriver: true,
    }).start();
  }, [fadeAnim]);

  return (
    <Animated.View style={{opacity: fadeAnim}}>
      {children}
    </Animated.View>
  );
}
```

#### 4.8.2 Animation Types

```tsx
// Spring animation
Animated.spring(value, {
  toValue: 1,
  friction: 5,
  tension: 40,
  useNativeDriver: true,
}).start();

// Timing animation with easing
import {Easing} from 'react-native';

Animated.timing(value, {
  toValue: 1,
  duration: 500,
  easing: Easing.bezier(0.25, 0.1, 0.25, 1),
  useNativeDriver: true,
}).start();

// Decay animation (momentum-based)
Animated.decay(value, {
  velocity: 0.95,
  deceleration: 0.997,
  useNativeDriver: true,
}).start();
```

#### 4.8.3 Composing Animations

```tsx
// Sequential
Animated.sequence([
  Animated.timing(opacity, {toValue: 1, duration: 300, useNativeDriver: true}),
  Animated.timing(translateY, {toValue: 0, duration: 300, useNativeDriver: true}),
]).start();

// Parallel
Animated.parallel([
  Animated.timing(opacity, {toValue: 1, duration: 300, useNativeDriver: true}),
  Animated.timing(scale, {toValue: 1, duration: 300, useNativeDriver: true}),
]).start();

// Stagger
Animated.stagger(100, [
  Animated.timing(item1Opacity, {toValue: 1, duration: 300, useNativeDriver: true}),
  Animated.timing(item2Opacity, {toValue: 1, duration: 300, useNativeDriver: true}),
  Animated.timing(item3Opacity, {toValue: 1, duration: 300, useNativeDriver: true}),
]).start();

// Loop
Animated.loop(
  Animated.sequence([
    Animated.timing(rotation, {toValue: 1, duration: 1000, useNativeDriver: true}),
    Animated.timing(rotation, {toValue: 0, duration: 1000, useNativeDriver: true}),
  ]),
).start();
```

#### 4.8.4 Interpolation

```tsx
const spinValue = useRef(new Animated.Value(0)).current;

const spin = spinValue.interpolate({
  inputRange: [0, 1],
  outputRange: ['0deg', '360deg'],
});

const backgroundColor = animValue.interpolate({
  inputRange: [0, 0.5, 1],
  outputRange: ['#e74c3c', '#f39c12', '#2ecc71'],
});

return (
  <Animated.View
    style={{
      transform: [{rotate: spin}],
      backgroundColor,
    }}
  />
);
```

### 4.9 Platform-Specific Code

#### 4.9.1 Platform Module

```tsx
import {Platform} from 'react-native';

// Simple check
if (Platform.OS === 'ios') {
  // iOS-specific code
} else if (Platform.OS === 'android') {
  // Android-specific code
}

// Version check
if (Platform.OS === 'android' && Platform.Version >= 33) {
  // Android 13+ specific code
}

// Platform.select
const styles = StyleSheet.create({
  container: {
    ...Platform.select({
      ios: {paddingTop: 44},
      android: {paddingTop: 0},
      default: {paddingTop: 0},
    }),
  },
});
```

#### 4.9.2 Platform-Specific Files

React Native automatically picks platform-specific files based on extension:

```
Button.ios.tsx      ← Used on iOS
Button.android.tsx  ← Used on Android
Button.tsx          ← Fallback for other platforms
```

Import normally — Metro resolves the correct file:

```tsx
import Button from './Button'; // Resolves to .ios.tsx or .android.tsx
```

### 4.10 Safe Area Handling

```tsx
import {SafeAreaView, StatusBar, StyleSheet} from 'react-native';

function App(): React.JSX.Element {
  return (
    <>
      <StatusBar barStyle="dark-content" backgroundColor="#fff" />
      <SafeAreaView style={styles.container}>
        {/* Your content here — respects notch, status bar, home indicator */}
      </SafeAreaView>
    </>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
});
```

For more control, use the community `react-native-safe-area-context` library:

```tsx
import {SafeAreaProvider, useSafeAreaInsets} from 'react-native-safe-area-context';

function Screen(): React.JSX.Element {
  const insets = useSafeAreaInsets();

  return (
    <View style={{paddingTop: insets.top, paddingBottom: insets.bottom}}>
      {/* Content */}
    </View>
  );
}

function App(): React.JSX.Element {
  return (
    <SafeAreaProvider>
      <Screen />
    </SafeAreaProvider>
  );
}
```

### 4.11 Debugging

#### 4.11.1 React Native DevTools

React Native ships with a built-in debugger based on Chrome DevTools. Access it via the Dev Menu (shake device or `Cmd+D` / `Cmd+M`).

The inspector proxy exposes these endpoints on the Metro dev server:

| Endpoint | Purpose |
|---|---|
| `/json` | List available debug targets |
| `/json/list` | Same as `/json` |
| `/json/version` | Version information |
| `/inspector/device` | Device connection endpoint |
| `/inspector/debug` | Debugger connection endpoint |

#### 4.11.2 Console Logging

```tsx
console.log('Info message');
console.warn('Warning message');  // Yellow box
console.error('Error message');   // Red box
```

Logs appear in:
- Metro terminal output
- React Native DevTools console
- Xcode console (iOS)
- Android Studio Logcat (Android): filter by `ReactNativeJS`

#### 4.11.3 React Developer Tools

Install the standalone React DevTools:

```bash
npx react-devtools
```

This opens a window that connects to your running app, allowing you to inspect the component tree, props, state, and hooks.

#### 4.11.4 Network Debugging

To inspect network requests, add to your app's entry point:

```tsx
// For debug builds only
if (__DEV__) {
  // XMLHttpRequest is used by fetch under the hood
  const originalXHR = global.XMLHttpRequest;
  // Use a network interceptor library or React Native DevTools
}
```

### 4.12 The New Architecture

React Native 0.86 defaults to the New Architecture, which consists of three pillars:

#### 4.12.1 Fabric (New Renderer)

Fabric replaces the old UI manager with a C++ renderer that enables:
- Synchronous layout and measurement
- Concurrent rendering support
- Better integration with platform views
- Improved performance through shared ownership of UI trees

No action required for JavaScript-level code — Fabric is transparent to your components.

#### 4.12.2 TurboModules

TurboModules replace the old bridge-based native modules with:
- Lazy loading (modules loaded only when first accessed)
- Direct JavaScript-to-native calls (no JSON serialization over the bridge)
- Type-safe interfaces via Codegen

#### 4.12.3 Codegen

Codegen generates type-safe C++ interfaces from your JavaScript/TypeScript/Flow type definitions. This ensures that JavaScript and native code always agree on the shape of data being passed.

---

## 5. Common Tasks

### 5.1 Storing Data Locally

#### 5.1.1 AsyncStorage

```bash
npm install @react-native-async-storage/async-storage
```

```tsx
import AsyncStorage from '@react-native-async-storage/async-storage';

// Store
await AsyncStorage.setItem('user_token', 'abc123');
await AsyncStorage.setItem('user_prefs', JSON.stringify({theme: 'dark'}));

// Retrieve
const token = await AsyncStorage.getItem('user_token');
const prefs = JSON.parse(await AsyncStorage.getItem('user_prefs') ?? '{}');

// Remove
await AsyncStorage.removeItem('user_token');

// Clear all
await AsyncStorage.clear();

// Multi operations
await AsyncStorage.multiSet([
  ['key1', 'value1'],
  ['key2', 'value2'],
]);

const values = await AsyncStorage.multiGet(['key1', 'key2']);
// values = [['key1', 'value1'], ['key2', 'value2']]
```

### 5.2 Handling Permissions

```bash
npm install react-native-permissions
```

```tsx
import {check, request, PERMISSIONS, RESULTS} from 'react-native-permissions';
import {Platform} from 'react-native';

async function requestCameraPermission() {
  const permission = Platform.select({
    ios: PERMISSIONS.IOS.CAMERA,
    android: PERMISSIONS.ANDROID.CAMERA,
  });

  if (!permission) return;

  const result = await check(permission);

  switch (result) {
    case RESULTS.UNAVAILABLE:
      console.log('Feature not available on this device');
      break;
    case RESULTS.DENIED:
      const requestResult = await request(permission);
      console.log('Request result:', requestResult);
      break;
    case RESULTS.GRANTED:
      console.log('Permission already granted');
      break;
    case RESULTS.BLOCKED:
      console.log('Permission blocked — direct user to Settings');
      break;
  }
}
```

### 5.3 Handling Deep Links

```tsx
import {Linking} from 'react-native';

// Open a URL
await Linking.openURL('https://example.com');

// Open phone dialer
await Linking.openURL('tel:+15551234567');

// Open email
await Linking.openURL('mailto:[email removed]');

// Open app settings
await Linking.openSettings();

// Listen for incoming deep links
useEffect(() => {
  const handleDeepLink = ({url}: {url: string}) => {
    console.log('Deep link received:', url);
    // Parse and navigate
  };

  // Check if app was opened via deep link
  Linking.getInitialURL().then(url => {
    if (url) handleDeepLink({url});
  });

  // Listen for deep links while app is open
  const subscription = Linking.addEventListener('url', handleDeepLink);
  return () => subscription.remove();
}, []);
```

### 5.4 Clipboard Operations

```tsx
import Clipboard from '@react-native-clipboard/clipboard';

// Copy to clipboard
Clipboard.setString('Text to copy');

// Read from clipboard
const text = await Clipboard.getString();
```

### 5.5 Using the Camera

```bash
npm install react-native-image-picker
```

```tsx
import {launchCamera, launchImageLibrary} from 'react-native-image-picker';

// Take a photo
const result = await launchCamera({
  mediaType: 'photo',
  quality: 0.8,
  maxWidth: 1024,
  maxHeight: 1024,
});

if (result.assets?.[0]) {
  const photo = result.assets[0];
  console.log('URI:', photo.uri);
  console.log('Size:', photo.fileSize);
}

// Pick from gallery
const picked = await launchImageLibrary({
  mediaType: 'mixed',
  selectionLimit: 5,
});
```

### 5.6 Showing Alerts and Action Sheets

```tsx
import {Alert, ActionSheetIOS, Platform} from 'react-native';

// Simple alert
Alert.alert('Title', 'Message');

// Alert with buttons
Alert.alert(
  'Delete Item',
  'Are you sure you want to delete this item?',
  [
    {text: 'Cancel', style: 'cancel'},
    {text: 'Delete', style: 'destructive', onPress: () => deleteItem()},
  ],
);

// Prompt for text input (iOS only)
Alert.prompt(
  'Enter Name',
  'Please enter your display name:',
  (text) => console.log('Entered:', text),
);

// Action Sheet (iOS)
if (Platform.OS === 'ios') {
  ActionSheetIOS.showActionSheetWithOptions(
    {
      options: ['Cancel', 'Share', 'Delete'],
      cancelButtonIndex: 0,
      destructiveButtonIndex: 2,
    },
    (buttonIndex) => {
      if (buttonIndex === 1) share();
      if (buttonIndex === 2) deleteItem();
    },
  );
}
```

### 5.7 Handling the Keyboard

```tsx
import React from 'react';
import {
  KeyboardAvoidingView,
  Platform,
  TextInput,
  StyleSheet,
  View,
} from 'react-native';

function ChatInput(): React.JSX.Element {
  return (
    <KeyboardAvoidingView
      behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
      keyboardVerticalOffset={Platform.OS === 'ios' ? 88 : 0}
      style={styles.container}>
      <View style={styles.inputRow}>
        <TextInput style={styles.input} placeholder="Type a message..." />
      </View>
    </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  inputRow: {
    flexDirection: 'row',
    padding: 8,
    borderTopWidth: 1,
    borderTopColor: '#eee',
  },
  input: {
    flex: 1,
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 20,
    paddingHorizontal: 16,
    paddingVertical: 8,
  },
});
```

#### 5.7.1 Keyboard Events

```tsx
import {Keyboard} from 'react-native';

useEffect(() => {
  const showSub = Keyboard.addListener('keyboardDidShow', (event) => {
    console.log('Keyboard height:', event.endCoordinates.height);
  });
  const hideSub = Keyboard.addListener('keyboardDidHide', () => {
    console.log('Keyboard hidden');
  });

  return () => {
    showSub.remove();
    hideSub.remove();
  };
}, []);

// Dismiss keyboard programmatically
Keyboard.dismiss();
```

### 5.8 StatusBar Configuration

```tsx
import {StatusBar} from 'react-native';

// Global configuration
<StatusBar
  barStyle="dark-content"     // 'dark-content' | 'light-content'
  backgroundColor="#ffffff"   // Android only
  translucent={false}         // Android only
  hidden={false}
/>

// Imperative API
StatusBar.setBarStyle('light-content');
StatusBar.setBackgroundColor('#000000'); // Android only
StatusBar.setHidden(true);
```

### 5.9 Sharing Content

```tsx
import {Share} from 'react-native';

async function shareContent() {
  try {
    const result = await Share.share({
      title: 'Check this out',
      message: 'I found something interesting: https://example.com',
      url: 'https://example.com', // iOS only
    });

    if (result.action === Share.sharedAction) {
      console.log('Shared successfully');
    } else if (result.action === Share.dismissedAction) {
      console.log('Share dismissed');
    }
  } catch (error) {
    console.error('Share error:', error);
  }
}
```

### 5.10 App State Handling

```tsx
import {AppState} from 'react-native';

useEffect(() => {
  const subscription = AppState.addEventListener('change', (nextAppState) => {
    if (nextAppState === 'active') {
      console.log('App came to foreground');
      // Refresh data, reconnect sockets, etc.
    } else if (nextAppState === 'background') {
      console.log('App went to background');
      // Save state, pause tasks, etc.
    } else if (nextAppState === 'inactive') {
      console.log('App is transitioning (iOS only)');
    }
  });

  return () => subscription.remove();
}, []);
```

### 5.11 Dimensions and Window Size

```tsx
import {Dimensions, useWindowDimensions} from 'react-native';

// Hook (recommended — updates on rotation)
function ResponsiveLayout(): React.JSX.Element {
  const {width, height} = useWindowDimensions();
  const isLandscape = width > height;

  return (
    <View style={{flexDirection: isLandscape ? 'row' : 'column'}}>
      {/* Responsive layout */}
    </View>
  );
}

// Static API (doesn't update on rotation)
const {width, height} = Dimensions.get('window');
const screenDimensions = Dimensions.get('screen'); // Includes status bar
```

### 5.12 Accessibility

```tsx
import {View, Text, TouchableOpacity} from 'react-native';

function AccessibleButton(): React.JSX.Element {
  return (
    <TouchableOpacity
      accessible={true}
      accessibilityLabel="Delete this item"
      accessibilityHint="Double tap to permanently remove this item"
      accessibilityRole="button"
      accessibilityState={{disabled: false}}
      onPress={handleDelete}>
      <Text>Delete</Text>
    </TouchableOpacity>
  );
}

// Live region (announces changes to screen reader)
<Text accessibilityLiveRegion="polite">
  {itemCount} items remaining
</Text>

// Accessibility roles
// 'button', 'link', 'header', 'search', 'image', 'text',
// 'adjustable', 'alert', 'checkbox', 'radio', 'switch', 'tab', etc.
```

### 5.13 Timers and Intervals

```tsx
import React, {useEffect, useRef} from 'react';

function useInterval(callback: () => void, delay: number | null) {
  const savedCallback = useRef(callback);

  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  useEffect(() => {
    if (delay === null) return;
    const id = setInterval(() => savedCallback.current(), delay);
    return () => clearInterval(id);
  }, [delay]);
}

// Usage
function Countdown(): React.JSX.Element {
  const [seconds, setSeconds] = useState(60);

  useInterval(() => {
    setSeconds(s => s - 1);
  }, seconds > 0 ? 1000 : null);

  return <Text>{seconds}s remaining</Text>;
}
```

### 5.14 Modal Dialogs

```tsx
import React, {useState} from 'react';
import {Modal, View, Text, Pressable, StyleSheet} from 'react-native';

function ModalExample(): React.JSX.Element {
  const [visible, setVisible] = useState(false);

  return (
    <>
      <Pressable onPress={() => setVisible(true)}>
        <Text>Open Modal</Text>
      </Pressable>

      <Modal
        animationType="slide"
        transparent={true}
        visible={visible}
        onRequestClose={() => setVisible(false)}>
        <View style={styles.modalOverlay}>
          <View style={styles.modalContent}>
            <Text style={styles.modalTitle}>Modal Title</Text>
            <Text>This is a modal dialog.</Text>
            <Pressable
              style={styles.closeButton}
              onPress={() => setVisible(false)}>
              <Text style={styles.closeText}>Close</Text>
            </Pressable>
          </View>
        </View>
      </Modal>
    </>
  );
}

const styles = StyleSheet.create({
  modalOverlay: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'rgba(0,0,0,0.5)',
  },
  modalContent: {
    backgroundColor: 'white',
    borderRadius: 16,
    padding: 24,
    width: '80%',
    alignItems: 'center',
  },
  modalTitle: {
    fontSize: 20,
    fontWeight: 'bold',
    marginBottom: 12,
  },
  closeButton: {
    marginTop: 16,
    paddingVertical: 8,
    paddingHorizontal: 24,
    backgroundColor: '#3498db',
    borderRadius: 8,
  },
  closeText: {
    color: 'white',
    fontWeight: '600',
  },
});
```

### 5.15 Appearance and Dark Mode

```tsx
import {useColorScheme, Appearance} from 'react-native';

function ThemedApp(): React.JSX.Element {
  const colorScheme = useColorScheme(); // 'light' | 'dark' | null

  const theme = {
    background: colorScheme === 'dark' ? '#1a1a1a' : '#ffffff',
    text: colorScheme === 'dark' ? '#ffffff' : '#1a1a1a',
    card: colorScheme === 'dark' ? '#2a2a2a' : '#f5f5f5',
  };

  return (
    <View style={{flex: 1, backgroundColor: theme.background}}>
      <Text style={{color: theme.text}}>
        Current scheme: {colorScheme}
      </Text>
    </View>
  );
}

// Imperative API
const current = Appearance.getColorScheme();
const listener = Appearance.addChangeListener(({colorScheme}) => {
  console.log('Theme changed to:', colorScheme);
});
```

### 5.16 Building Production Apps

#### 5.16.1 Bundle for Production

```bash
# Create the JavaScript bundle
npx react-native bundle \
  --platform ios \
  --dev false \
  --entry-file index.js \
  --bundle-output ios/main.jsbundle \
  --assets-dest ios

npx react-native bundle \
  --platform android \
  --dev false \
  --entry-file index.js \
  --bundle-output android/app/src/main/assets/index.android.bundle \
  --assets-dest android/app/src/main/res
```

#### 5.16.2 Build Android Release APK/AAB

```bash
cd android
./gradlew assembleRelease    # APK
./gradlew bundleRelease      # AAB (recommended for Play Store)
```

Output locations:

```
android/app/build/outputs/apk/release/app-release.apk
android/app/build/outputs/bundle/release/app-release.aab
```

> [!IMPORTANT]
> Release builds require a signing key. Configure signing in `android/app/build.gradle` under `signingConfigs` before building. Without proper signing, the app will not install on devices or be accepted by the Play Store.

#### 5.16.3 Build iOS Release

1. Open `ios/MyProject.xcworkspace` in Xcode
2. Select "Any iOS Device" as the build target
3. Product > Archive
4. In the Organizer window, select the archive and click "Distribute App"

### 5.17 Environment Variables

```bash
# Set during Metro start
RCT_METRO_PORT=8088 npx react-native start

# Check dev mode in code
if (__DEV__) {
  console.log('Running in development mode');
}
```

For more comprehensive environment variable management, use a library like `react-native-config`:

```bash
npm install react-native-config
```

```
# .env
API_URL=https://api.example.com
API_KEY=your_api_key
```

```tsx
import Config from 'react-native-config';

console.log(Config.API_URL); // 'https://api.example.com'
```

### 5.18 Custom Fonts

#### 5.18.1 Using Static Assets

1. Place font files in `assets/fonts/` directory
2. Add to `react-native.config.js`:

```javascript
module.exports = {
  project: {
    ios: {},
    android: {},
  },
  assets: ['./assets/fonts/'],
};
```

3. Link the fonts:

```bash
npx react-native-asset
```

4. Use in styles:

```tsx
const styles = StyleSheet.create({
  text: {
    fontFamily: 'Montserrat-Bold', // Exact filename without extension
  },
});
```

### 5.19 Error Boundaries

```tsx
import React from 'react';
import {View, Text, Button, StyleSheet} from 'react-native';

interface ErrorBoundaryState {
  hasError: boolean;
  error: Error | null;
}

class ErrorBoundary extends React.Component<
  {children: React.ReactNode},
  ErrorBoundaryState
> {
  constructor(props: {children: React.ReactNode}) {
    super(props);
    this.state = {hasError: false, error: null};
  }

  static getDerivedStateFromError(error: Error) {
    return {hasError: true, error};
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    // Log to crash reporting service
    console.error('ErrorBoundary caught:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return (
        <View style={styles.container}>
          <Text style={styles.title}>Something went wrong</Text>
          <Text style={styles.message}>{this.state.error?.message}</Text>
          <Button
            title="Try Again"
            onPress={() => this.setState({hasError: false, error: null})}
          />
        </View>
      );
    }
    return this.props.children;
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  title: {
    fontSize: 20,
    fontWeight: 'bold',
    marginBottom: 8,
  },
  message: {
    color: '#666',
    marginBottom: 16,
    textAlign: 'center',
  },
});
```

### 5.20 Performance Optimization

#### 5.20.1 Memoization

```tsx
import React, {useMemo, useCallback} from 'react';

// Memoize expensive computations
const sortedData = useMemo(() => {
  return data.sort((a, b) => a.name.localeCompare(b.name));
}, [data]);

// Memoize callbacks
const handlePress = useCallback((id: string) => {
  setSelectedId(id);
}, []);

// Memoize components
const MemoizedItem = React.memo(function Item({title, onPress}: ItemProps) {
  return (
    <Pressable onPress={onPress}>
      <Text>{title}</Text>
    </Pressable>
  );
});
```

#### 5.20.2 FlatList Optimization

```tsx
<FlatList
  data={data}
  renderItem={renderItem}
  keyExtractor={keyExtractor}
  // Performance props
  removeClippedSubviews={true}       // Unmount off-screen views
  maxToRenderPerBatch={10}           // Items per render batch
  updateCellsBatchingPeriod={50}     // Batch update interval (ms)
  windowSize={5}                     // Render window multiplier
  initialNumToRender={10}            // Initial render count
  getItemLayout={(data, index) => ({ // Skip measurement
    length: ITEM_HEIGHT,
    offset: ITEM_HEIGHT * index,
    index,
  })}
/>
```

#### 5.20.3 Image Optimization

```tsx
// Use FastImage for better caching (community library)
import FastImage from 'react-native-fast-image';

<FastImage
  style={{width: 200, height: 200}}
  source={{
    uri: 'https://example.com/photo.jpg',
    priority: FastImage.priority.normal,
    cache: FastImage.cacheControl.immutable,
  }}
  resizeMode={FastImage.resizeMode.cover}
/>
```

### 5.21 Testing

#### 5.21.1 Unit Tests with Jest

```tsx
// __tests__/utils.test.ts
import {formatCurrency, validateEmail} from '../src/utils';

describe('formatCurrency', () => {
  it('formats dollars correctly', () => {
    expect(formatCurrency(1234.5)).toBe('$1,234.50');
  });

  it('handles zero', () => {
    expect(formatCurrency(0)).toBe('$0.00');
  });
});

describe('validateEmail', () => {
  it('accepts valid emails', () => {
    expect(validateEmail('[email removed]')).toBe(true);
  });

  it('rejects invalid emails', () => {
    expect(validateEmail('not-an-email')).toBe(false);
  });
});
```

Run tests:

```bash
npx jest

# With coverage
npx jest --coverage

# Watch mode
npx jest --watch
```

#### 5.21.2 Component Tests

```tsx
// __tests__/Counter.test.tsx
import React from 'react';
import {render, fireEvent} from '@testing-library/react-native';
import Counter from '../src/Counter';

describe('Counter', () => {
  it('renders initial count', () => {
    const {getByText} = render(<Counter />);
    expect(getByText('Count: 0')).toBeTruthy();
  });

  it('increments on press', () => {
    const {getByText} = render(<Counter />);
    fireEvent.press(getByText('Increment'));
    expect(getByText('Count: 1')).toBeTruthy();
  });
});
```

#### 5.21.3 Snapshot Tests

```tsx
import React from 'react';
import renderer from 'react-test-renderer';
import App from '../App';

it('renders correctly', () => {
  const tree = renderer.create(<App />).toJSON();
  expect(tree).toMatchSnapshot();
});
```

### 5.22 Upgrading React Native

```bash
# Check available upgrade
npx react-native upgrade

# Or use the upgrade helper website to see diffs between versions:
# https://react-native-community.github.io/upgrade-helper/
```

> [!CAUTION]
> Major version upgrades can involve breaking changes to native code, Gradle configurations, Podfile settings, and third-party library compatibility. Always read the release notes, back up your project, and test thoroughly on both platforms after upgrading.

### 5.23 Using Native Modules (TurboModules)

With the New Architecture, native modules use Codegen for type-safe bridging.

#### 5.23.1 Defining a TurboModule Spec (TypeScript)

```tsx
// NativeCalculator.ts
import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';

export interface Spec extends TurboModule {
  add(a: number, b: number): number;
  multiply(a: number, b: number): Promise<number>;
}

export default TurboModuleRegistry.getEnforcing<Spec>('Calculator');
```

#### 5.23.2 Using the Module

```tsx
import NativeCalculator from './NativeCalculator';

const sum = NativeCalculator.add(3, 4); // Synchronous: 7
const product = await NativeCalculator.multiply(3, 4); // Async: 12
```

### 5.24 Handling Back Button (Android)

```tsx
import {BackHandler} from 'react-native';

useEffect(() => {
  const backAction = () => {
    if (canGoBack) {
      goBack();
      return true; // Prevent default behavior
    }
    return false; // Let system handle it
  };

  const backHandler = BackHandler.addEventListener(
    'hardwareBackPress',
    backAction,
  );

  return () => backHandler.remove();
}, [canGoBack]);
```

### 5.25 Vibration and Haptic Feedback

```tsx
import {Vibration} from 'react-native';

// Simple vibration
Vibration.vibrate();

// Duration (Android only; iOS ignores the duration)
Vibration.vibrate(500);

// Pattern: [wait, vibrate, wait, vibrate, ...]
Vibration.vibrate([500, 1000, 500, 2000]);

// Cancel
Vibration.cancel();
```

### 5.26 Using the PixelRatio API

```tsx
import {PixelRatio} from 'react-native';

// Get device pixel density
const density = PixelRatio.get(); // e.g., 2 for @2x, 3 for @3x

// Convert layout size to pixel size
const pixelSize = PixelRatio.getPixelSizeForLayoutSize(100);

// Round to nearest pixel
const rounded = PixelRatio.roundToNearestPixel(8.4);

// Get font scale
const fontScale = PixelRatio.getFontScale();
```

---

## 6. Troubleshooting

### 6.1 Build and Setup Issues

#### Error: "Unable to load script from assets 'index.android.bundle'"

**Cause:** The JavaScript bundle is not being served to the Android emulator or device.

**Solution:**
1. Ensure Metro is running: `npx react-native start`
2. If using a physical device, ensure it's on the same network as your development machine
3. For the emulator, reverse the port:
   ```bash
   adb reverse tcp:8081 tcp:8081
   ```
4. If the port was changed, use the correct port:
   ```bash
   adb reverse tcp:8088 tcp:8088
   ```

**Prevention:** Always start Metro before running the app. If using a custom port via `RCT_METRO_PORT`, ensure it matches everywhere.

#### Error: "Build failed" with CocoaPods issues

**Cause:** Stale or corrupt CocoaPods cache, or mismatched dependency versions.

**Solution:**
1. Clean and reinstall:
   ```bash
   cd ios
   rm -rf Pods Podfile.lock
   pod cache clean --all
   pod install
   cd ..
   ```
2. If that fails, also clean the build folder:
   ```bash
   cd ios
   xcodebuild clean
   cd ..
   ```

**Prevention:** Run `pod install` after every `npm install` that adds native dependencies.

#### Error: "Inconsistent Podfile.lock checksums for hermes-engine"

**Cause:** The Podfile.lock has cached checksums that don't match the current Hermes binary. This is a known issue (GitHub #54891) that can occur after upgrading React Native or switching branches.

**Solution:**
1. Delete the lockfile and reinstall:
   ```bash
   cd ios
   rm Podfile.lock
   pod install
   cd ..
   ```
2. If the error persists, clean the CocoaPods cache for Hermes specifically:
   ```bash
   pod cache clean hermes-engine
   pod install
   ```

**Prevention:** Always delete `Podfile.lock` before running `pod install` after a React Native version upgrade.

#### Error: "SDK location not found"

**Cause:** `ANDROID_HOME` environment variable is not set or points to the wrong location.

**Solution:**
1. Find your Android SDK location (check Android Studio > Settings > SDK Manager)
2. Set the environment variable:
   ```bash
   export ANDROID_HOME=$HOME/Library/Android/sdk  # macOS
   export ANDROID_HOME=$HOME/Android/Sdk           # Linux
   ```
3. Add to your shell profile (`~/.zshrc`, `~/.bashrc`)

**Prevention:** Add `ANDROID_HOME` to your shell profile during initial setup.

#### Error: "foojay-resolver-convention 0.5.0 incompatible with Gradle 9.0.0"

**Cause:** The `foojay-resolver-convention` plugin version bundled with React Native is too old for Gradle 9.x. This is a known issue (GitHub #56287).

**Solution:**
1. In `android/settings.gradle`, update the plugin version:
   ```groovy
   plugins {
       id 'org.gradle.toolchains.foojay-resolver-convention' version '0.9.0'
   }
   ```
2. Or downgrade to a compatible Gradle version in `android/gradle/wrapper/gradle-wrapper.properties`:
   ```properties
   distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
   ```

**Prevention:** Check Gradle compatibility before upgrading Android build tools.

### 6.2 Runtime Errors

#### Error: "Invariant Violation: requireNativeComponent: 'RCTView' was not found"

**Cause:** Native components are not properly linked, typically after adding a library with native code.

**Solution:**
1. For iOS:
   ```bash
   cd ios && pod install && cd ..
   npx react-native run-ios
   ```
2. For Android, rebuild:
   ```bash
   cd android && ./gradlew clean && cd ..
   npx react-native run-android
   ```

**Prevention:** Always run `pod install` (iOS) and rebuild after adding libraries with native dependencies.

#### Error: "VirtualizedLists should never be nested inside plain ScrollViews"

**Cause:** A `FlatList` or `SectionList` is placed inside a `ScrollView`, creating competing scroll containers.

**Solution:**
1. Replace the outer `ScrollView` with a `View`
2. Or use `FlatList`'s `ListHeaderComponent` and `ListFooterComponent` for content above/below the list
3. Or use the `nestedScrollEnabled` prop (Android only, not recommended)

```tsx
// Instead of this:
<ScrollView>
  <Header />
  <FlatList data={data} renderItem={renderItem} />
</ScrollView>

// Do this:
<FlatList
  data={data}
  renderItem={renderItem}
  ListHeaderComponent={<Header />}
/>
```

**Prevention:** Design layouts so `FlatList`/`SectionList` is the outermost scrolling container.

#### Error: "Animations do not run correctly in React Navigation"

**Cause:** A known issue (GitHub #56347) where `Animated` animations conflict with React Navigation's transition animations on iOS, particularly when using `Animated.timing` inside screen components.

**Solution:**
1. Use `useNativeDriver: true` in all animations
2. Defer animations until after the navigation transition completes:
   ```tsx
   useFocusEffect(
     useCallback(() => {
       // Start animations here, after screen is focused
       Animated.timing(opacity, {
         toValue: 1,
         duration: 300,
         useNativeDriver: true,
       }).start();
     }, []),
   );
   ```
3. Consider using `react-native-reanimated` for more complex animation scenarios

**Prevention:** Always use `useNativeDriver: true` and tie animations to navigation lifecycle events.

#### Error: "Network request failed"

**Cause:** This intermittent error (GitHub #56480) can stem from multiple causes: network timeout, SSL certificate issues, or Android cleartext traffic restrictions.

**Solution:**
1. On Android, ensure cleartext traffic is allowed for development:
   ```xml
   <!-- android/app/src/main/AndroidManifest.xml -->
   <application android:usesCleartextTraffic="true" ...>
   ```
2. Check network connectivity
3. Add error retry logic:
   ```tsx
   async function fetchWithRetry(url: string, retries = 3) {
     for (let i = 0; i < retries; i++) {
       try {
         const response = await fetch(url);
         return response;
       } catch (error) {
         if (i === retries - 1) throw error;
         await new Promise(r => setTimeout(r, 1000 * (i + 1)));
       }
     }
   }
   ```

**Prevention:** Implement retry logic and timeout handling for all network requests.

#### Error: App crashes on startup with "TurboModule performVoidMethodInvocation - SIGABRT" (iOS)

**Cause:** A known issue on iOS 26 (GitHub #54859) where TurboModule initialization triggers a crash during app startup. This affects apps using the New Architecture.

**Solution:**
1. Check if you're running on the latest React Native patch version — this may have a fix
2. If on an older version, try disabling specific TurboModules that may be causing the crash
3. Check the GitHub issue for the latest workarounds specific to your iOS version

**Prevention:** Test on the latest iOS betas early and track known issues in the React Native repository.

#### Error: "EXC_BAD_ACCESS in production after upgrading"

**Cause:** Memory corruption, often related to the Fabric renderer or native module lifecycle changes between React Native versions (GitHub #53774).

**Solution:**
1. Clean all build caches:
   ```bash
   cd ios
   rm -rf Pods Podfile.lock build DerivedData
   pod install
   cd ..
   npx react-native run-ios --mode Release
   ```
2. If persists, check for native modules that haven't been updated for the current React Native version
3. Test with native modules removed one at a time to isolate the cause

**Prevention:** After upgrading React Native, test release builds on physical devices before deploying to users.

### 6.3 UI and Layout Issues

#### Visual jump when using RefreshControl

**Cause:** A longstanding issue (GitHub #31461) where `RefreshControl` causes the list to jump to an unexpected scroll position when the refresh animation begins.

**Solution:**
1. Set `progressViewOffset` on Android to adjust the refresh indicator position:
   ```tsx
   <FlatList
     refreshControl={
       <RefreshControl
         refreshing={refreshing}
         onRefresh={onRefresh}
         progressViewOffset={Platform.OS === 'android' ? 50 : 0}
       />
     }
   />
   ```
2. On iOS, wrapping in a fixed-height container can help mitigate the jump

**Prevention:** Test pull-to-refresh behavior across both platforms during development.

#### Nested Text not focusable by hardware keyboard

**Cause:** A known issue (GitHub #35194) where nested `<Text>` components inside tappable elements cannot receive focus from hardware keyboards or accessibility devices.

**Solution:**
1. Use `accessible={true}` on the outermost tappable container
2. Set `accessibilityRole="link"` or `accessibilityRole="button"` on the container
3. For keyboard navigation, consider wrapping tappable text in a `Pressable`:
   ```tsx
   <Pressable onPress={handlePress} accessible accessibilityRole="link">
     <Text>
       Read the <Text style={{color: 'blue'}}>documentation</Text>
     </Text>
   </Pressable>
   ```

**Prevention:** Always test with hardware keyboards and screen readers.

#### Nested View and Text vertical alignment issue

**Cause:** When mixing `View` and `Text` components in a row layout, vertical alignment can be inconsistent because `Text` components use text baseline alignment while `View` components use their box model (GitHub #31955).

**Solution:**
1. Use `alignItems: 'center'` on the parent flex row
2. Ensure the `View` and `Text` have explicit matching heights
3. Apply `textAlignVertical: 'center'` (Android) to `Text` components

**Prevention:** Use consistent component types in flex rows. Wrap mixed content in `View` containers with explicit alignment.

#### letterSpacing not working properly

**Cause:** A known issue (GitHub #54823) where `letterSpacing` behaves inconsistently across platforms, particularly with certain font families and sizes.

**Solution:**
1. Test `letterSpacing` values on both platforms
2. Use platform-specific values if needed:
   ```tsx
   const styles = StyleSheet.create({
     text: {
       letterSpacing: Platform.select({ios: 1.5, android: 2}),
     },
   });
   ```

**Prevention:** Always verify text styling on both iOS and Android.

#### KeyboardAvoidingView not keeping input visible (Android 15)

**Cause:** On Android 15, the keyboard insets reported to `KeyboardAvoidingView` can be incorrect, causing the input field to remain hidden behind the keyboard (GitHub #49759).

**Solution:**
1. Use `behavior="height"` instead of `behavior="padding"` on Android:
   ```tsx
   <KeyboardAvoidingView
     behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
     keyboardVerticalOffset={Platform.select({ios: 88, android: 0})}>
     {/* Input fields */}
   </KeyboardAvoidingView>
   ```
2. Alternatively, use `android:windowSoftInputMode="adjustResize"` in `AndroidManifest.xml`
3. Consider `react-native-keyboard-aware-scroll-view` as a community alternative

**Prevention:** Test keyboard behavior on the latest Android versions during development.

#### getStatusBarHeightPx initialized before DecorView attached

**Cause:** On some Android devices, `StatusBar` height methods are called before the view hierarchy is ready (GitHub #53251), returning 0 or incorrect values.

**Solution:**
1. Defer status bar height reads to after `onLayout`:
   ```tsx
   <View
     onLayout={() => {
       // StatusBar height is now reliable
       const height = StatusBar.currentHeight;
     }}
   />
   ```
2. Use `react-native-safe-area-context` which handles this timing correctly

**Prevention:** Avoid reading `StatusBar.currentHeight` in component constructors or early lifecycle methods.

### 6.4 Development Server Issues

#### Error: "Could not connect to development server"

**Cause:** Metro is not running, or the device cannot reach the dev server.

**Solution:**
1. Start Metro: `npx react-native start`
2. On Android emulator, set up port forwarding:
   ```bash
   adb reverse tcp:8081 tcp:8081
   ```
3. On physical device, ensure same Wi-Fi network and correct IP
4. Check if another process is using port 8081:
   ```bash
   lsof -i :8081
   ```
5. Use a different port:
   ```bash
   RCT_METRO_PORT=8088 npx react-native start
   ```

**Prevention:** Kill stale Metro processes before starting a new one.

#### Error: "EMFILE: too many open files"

**Cause:** Metro's file watcher exceeds the OS file descriptor limit.

**Solution:**
1. Install Watchman (recommended for all platforms):
   ```bash
   brew install watchman   # macOS
   ```
2. On Linux, increase the limit:
   ```bash
   echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
   sudo sysctl -p
   ```

**Prevention:** Install Watchman as part of initial setup.

#### Metro bundler stuck or stale cache

**Cause:** Metro's cache can become corrupted after branch switches, dependency changes, or interrupted builds.

**Solution:**
1. Start Metro with a clean cache:
   ```bash
   npx react-native start --reset-cache
   ```
2. Delete the Metro cache directory manually:
   ```bash
   rm -rf $TMPDIR/metro-*
   rm -rf $TMPDIR/haste-map-*
   ```

**Prevention:** Use `--reset-cache` after major changes like upgrading React Native or switching branches with different dependency trees.

### 6.5 Android-Specific Issues

#### Broken code completion / IntelliSense in Android Studio

**Cause:** A known issue (GitHub #55517) where Android Studio's code completion fails for React Native projects due to Gradle sync or indexing issues with the React Native Gradle plugin.

**Solution:**
1. Invalidate caches and restart: File > Invalidate Caches / Restart
2. Re-sync Gradle: File > Sync Project with Gradle Files
3. Ensure Android Studio is updated to the latest stable version

**Prevention:** Keep Android Studio and the Android Gradle plugin at compatible versions.

#### Hermes profiling: heap snapshot fails with OkHttp WebSocket overflow

**Cause:** When taking heap snapshots via Hermes CDP, OkHttp's WebSocket queue can overflow (GitHub #56470), causing the connection to close before the snapshot completes.

**Solution:**
1. Use React Native DevTools instead of Chrome DevTools for heap profiling
2. Reduce memory pressure before taking snapshots (close other apps, reduce data in state)
3. If using a custom CDP client, increase WebSocket buffer sizes

**Prevention:** Use the built-in React Native DevTools for Hermes debugging tasks.

#### HermesSamplingProfiler JNI method mismatch

**Cause:** A known issue (GitHub #56126) where the JNI "disable" method is incorrectly mapped to the native `enable` function, potentially causing profiling to behave unexpectedly on Android.

**Solution:**
1. Check if a patch is available for your React Native version
2. Avoid using the Hermes sampling profiler until the fix is released
3. Use the JavaScript profiler in React Native DevTools as an alternative

**Prevention:** Monitor the GitHub issue for resolution in upcoming releases.

### 6.6 Performance Issues

#### App feels slow / janky scrolling

**Cause:** Heavy computation on the JavaScript thread blocks the UI.

**Solution:**
1. Move to native driver for animations:
   ```tsx
   Animated.timing(value, {
     toValue: 1,
     useNativeDriver: true, // Key for performance
   }).start();
   ```
2. Optimize `FlatList` (see section 5.20.2)
3. Use `React.memo` for list items
4. Avoid inline functions in `renderItem`:
   ```tsx
   // Bad — creates new function every render
   renderItem={({item}) => <Item data={item} onPress={() => select(item.id)} />}

   // Good — stable reference
   const renderItem = useCallback(({item}) => (
     <Item data={item} onPress={handlePress} />
   ), [handlePress]);
   ```

**Prevention:** Profile regularly with the React DevTools Profiler and Systrace.

#### Large bundle size

**Cause:** Unused code, large assets, or unoptimized dependencies.

**Solution:**
1. Enable inline requires (already default in Metro config: `inlineRequires: true`)
2. Analyze bundle size:
   ```bash
   npx react-native bundle \
     --platform android \
     --dev false \
     --entry-file index.js \
     --bundle-output /tmp/bundle.js \
     --sourcemap-output /tmp/bundle.map

   npx source-map-explorer /tmp/bundle.js /tmp/bundle.map
   ```
3. Remove unused dependencies from `package.json`
4. Use dynamic imports for rarely-used features

**Prevention:** Monitor bundle size as part of your CI/CD pipeline.

### 6.7 General Debugging Strategies

#### Full cache reset (nuclear option)

When nothing else works, clear everything:

```bash
# Stop Metro
# Kill all running emulators/simulators

# Clear JS/Node caches
rm -rf node_modules
npm cache clean --force
npm install

# Clear Metro cache
rm -rf $TMPDIR/metro-*
rm -rf $TMPDIR/haste-map-*

# Clear iOS caches
cd ios
rm -rf Pods Podfile.lock build
pod cache clean --all
pod install
cd ..

# Clear Android caches
cd android
./gradlew clean
cd ..

# Clear Xcode DerivedData
rm -rf ~/Library/Developer/Xcode/DerivedData

# Restart Metro with clean cache
npx react-native start --reset-cache
```

> [!WARNING]
> The full cache reset deletes significant build artifacts and caches. Expect longer build times for the next build as everything is regenerated from scratch. Only use this when targeted solutions have failed.

---

## 7. FAQ

**Q: What JavaScript engine does React Native use?**

React Native uses Hermes as its default JavaScript engine. Hermes is an open-source engine optimized for React Native with ahead-of-time compilation, lower memory usage, and faster startup compared to JavaScriptCore. It is built in and enabled by default.

**Q: Can I use TypeScript with React Native?**

Yes. New projects created with `npx @react-native-community/cli@latest init` include TypeScript support out of the box, with a `tsconfig.json` that extends `@react-native/typescript-config`. You can write all your components in `.tsx` files.

**Q: What is the New Architecture?**

The New Architecture is the modernized internals of React Native, consisting of three components: Fabric (the new renderer for UI), TurboModules (the new native module system with lazy loading and direct calls), and Codegen (type-safe bridge code generation). It is enabled by default in React Native 0.86.

**Q: Can I build for both iOS and Android from a single codebase?**

Yes, that is React Native's primary purpose. You write your UI components and business logic once in JavaScript/TypeScript, and React Native renders native views on each platform. Platform-specific code can be handled via `Platform.OS` checks, `Platform.select()`, or platform-specific file extensions (`.ios.tsx`, `.android.tsx`).

**Q: Can I use npm packages from the web ecosystem?**

Many npm packages work in React Native, particularly those that are pure JavaScript. Packages that depend on browser-specific APIs (DOM, `window`, `document`, Canvas, etc.) will not work. Always check a package's React Native compatibility before installing.

**Q: How do I handle different screen sizes?**

Use Flexbox for responsive layouts, `useWindowDimensions()` for dimension-aware rendering, percentage-based widths/heights, and `PixelRatio` for pixel-perfect designs. React Native's Flexbox implementation handles density-independent pixels automatically.

**Q: What is Metro?**

Metro is React Native's JavaScript bundler. It watches your source files, transforms them through Babel, resolves dependencies, and serves the bundle to your app. It runs on port 8081 by default (configurable via `RCT_METRO_PORT`). The default configuration resolves modules using the field order `['react-native', 'browser', 'main']` and supports the platforms `['android', 'ios']`.

**Q: How do I add custom native code?**

For the New Architecture, create a TurboModule specification in TypeScript/Flow, then implement the native side in Swift/Objective-C (iOS) or Kotlin/Java (Android). Codegen generates the C++ bridge code. For Fabric components, define a component spec and implement the native view. See the Admin Guide for architecture details.

**Q: What is Fast Refresh?**

Fast Refresh is React Native's hot reloading system. When you save a file, Metro sends only the changed module to the running app, which updates the component tree while preserving state. It handles both functional and class components, and falls back to a full reload when structural changes require it.

**Q: How do I debug React Native apps?**

React Native includes a built-in debugger based on Chrome DevTools (`@react-native/debugger-frontend`). Access it via the Dev Menu (shake device, `Cmd+D`, or `Cmd+M`). You can also use `npx react-devtools` for component tree inspection, or the inspector proxy endpoints (`/json`, `/json/list`, `/json/version`) for custom debugger integrations.

**Q: Do I need a Mac to build for iOS?**

Yes. iOS apps can only be built on macOS with Xcode installed. There is no way around this Apple platform requirement. For teams without Mac hardware, cloud Mac services (like Mac Stadium or GitHub Actions macOS runners) are common solutions.

**Q: How do I handle navigation between screens?**

React Native does not include a built-in navigation library. The community standard is React Navigation (`@react-navigation`), which provides stack, tab, drawer, and other navigation patterns. See section 4.5 for setup and usage examples.

**Q: Can I use React Native with Expo?**

Yes. Expo is a popular framework built on top of React Native that provides additional tooling, pre-configured native modules, and a managed workflow. This guide focuses on the bare React Native CLI workflow, but many concepts apply to both.

**Q: How do I handle images with different resolutions?**

For local images, provide `@1x`, `@2x`, and `@3x` variants:

```
assets/
  logo.png       (100x100)
  logo@2x.png    (200x200)
  logo@3x.png    (300x300)
```

React Native's asset system (backed by `@react-native/assets-registry`) automatically selects the correct variant for the device's pixel density.

**Q: What is the difference between `ScrollView` and `FlatList`?**

`ScrollView` renders all children at once — suitable for small, fixed-size content. `FlatList` virtualizes its children, only rendering items visible on screen — required for large or dynamic lists. Use `FlatList` (or `SectionList`) whenever your list has more than a few dozen items.

**Q: How do I handle forms and validation?**

React Native provides `TextInput` for form fields. For form management and validation, community libraries like Formik or React Hook Form work well with React Native. These are standard React libraries that are fully compatible.

**Q: How do I add splash screens?**

React Native does not include built-in splash screen support. Use the community library `react-native-splash-screen` or `react-native-bootsplash`. Configure the native splash screen in Xcode (LaunchScreen.storyboard) and Android (`styles.xml` theme).

**Q: Can I use web CSS in React Native?**

No. React Native uses a JavaScript-based styling system that resembles CSS but has key differences: all properties are camelCase, dimensions are unitless (density-independent pixels), `flexDirection` defaults to `column`, there is no cascading or inheritance (except within `Text`), and not all CSS properties are supported. Use `StyleSheet.create()` for all styles.

**Q: How do I handle offline/no-network scenarios?**

Use the `NetInfo` community library (`@react-native-community/netinfo`) to detect connectivity status. Combine with local storage (AsyncStorage or SQLite) to cache data for offline use. Implement retry queues for failed network requests.

**Q: What are the supported platforms?**

React Native officially supports iOS and Android. The Metro configuration defaults to `platforms: ['android', 'ios']`. Community-driven efforts extend support to Windows, macOS, web, and other targets via out-of-tree platforms.

**Q: How do I handle app permissions?**

Use the `react-native-permissions` community library for a cross-platform permissions API. On iOS, configure required permission descriptions in `Info.plist`. On Android, declare permissions in `AndroidManifest.xml`. See section 5.2 for examples.

**Q: Why is my app's startup time slow?**

Common causes: large JavaScript bundle, too many modules loaded at startup, heavy initial rendering. Solutions: enable Hermes (default), use inline requires (enabled by default in Metro), lazy-load screens, minimize initial render tree, and profile with Hermes bytecode compilation stats.

**Q: How do I use environment variables?**

React Native provides `__DEV__` globally to check if you're in development mode. For custom environment variables, use the `react-native-config` library or set them via `RCT_METRO_PORT` and similar env vars at build time. Do not hardcode secrets in your JavaScript bundle.

**Q: Can I share code between React Native and React web?**

Yes, with caveats. Business logic, hooks, state management, and API calls can be shared. UI components cannot be shared directly because React Native uses `View`/`Text` instead of `div`/`span`. Libraries like React Native Web bridge this gap by mapping React Native components to web equivalents.

**Q: How do I profile my app's performance?**

Use the React DevTools Profiler for component render profiling. Use Systrace for native-level profiling. On Android, use Android Studio's profiler. On iOS, use Xcode Instruments. The Hermes profiler provides JavaScript-specific profiling data.

**Q: What is the `__DEV__` variable?**

`__DEV__` is a global boolean set to `true` in development builds and `false` in production builds. Use it to conditionally include debug logging, development tools, or mock data:

```tsx
if (__DEV__) {
  console.log('Debug info:', data);
}
```

**Q: How do I handle the Android hardware back button?**

Use `BackHandler` from React Native (see section 5.24). Return `true` from the handler to prevent the default back behavior, or `false` to allow it. React Navigation handles back button integration automatically for its navigation stacks.

---

_Generated May 2026 from facebook/react-native at ba204fa. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
