mcpField
R
react-native

react-native

github.com/jezweb開発1.1k1.3k 回インストール3 週間前に更新
リポジトリ

react-native について

React Native と Expo の開発者向けに、モバイルアプリの性能と設計パターンを影響度順にまとめたガイドです。リスト、アニメーション、ナビゲーション、Expo のワークフローを扱います。

主な機能

  1. 01影響度順のルール
  2. 02リストとスクロールの性能対策
  3. 03アニメーションとジェスチャーのパターン
  4. 04ナビゲーションと UI の指針
  5. 05状態、データ、メディアの指針
  6. 06Expo のワークフローとテスト

活用シーン

  1. 01React Native または Expo アプリの新規作成
  2. 02リストのスクロールの遅さの調査
  3. 03モバイルアプリの性能レビュー
  4. 04Expo プロジェクトとテストの設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jezweb/claude-skills --skill react-native

インストール後、Claude Code で/react-nativeを入力して読み込まれたか確認します。

詳細

React Native のパターン

React Native + Expo アプリのパフォーマンスとアーキテクチャに関するパターンです。影響度の高い順にルールを並べています。MEDIUM に取り組む前に、CRITICAL を解決してください。

これは出発点です。モバイルアプリをさらに構築するにつれて、このスキルは成長していきます。

適用する場面

  • 新しい React Native または Expo アプリを構築するとき
  • リストやスクロールのパフォーマンスを最適化するとき
  • アニメーションを実装するとき
  • パフォーマンス上の問題がないかモバイルコードをレビューするとき
  • 新しい Expo プロジェクトをセットアップするとき

1. リストのパフォーマンス(CRITICAL)

リストは、React Native におけるパフォーマンスの問題の第 1 位です。スクロールがカクつくと、アプリ全体の使用感が損なわれます。

パターン問題解決策
データ表示に ScrollView を使用<ScrollView> はすべてのアイテムを一度に描画します<FlatList> または <FlashList> を使用します。仮想化されており、表示中のアイテムだけを描画します
keyExtractor がないkeyExtractor のない FlatList は不要な再レンダリングが発生しますkeyExtractor={(item) => item.id} を指定します。各アイテムに安定した一意のキーを設定します
複雑な renderItemrenderItem 内の負荷の高いコンポーネントは、スクロールのたびに再レンダリングされますReact.memo でラップし、別のコンポーネントに切り出します
renderItem 内のインライン関数renderItem={({ item }) => <Row onPress={() => nav(item.id)} />}ハンドラーを切り出します:const handlePress = useCallback(...)
getItemLayout がないFlatList はスクロール時に各アイテムのサイズを測定します(負荷が高くなります)高さが固定のアイテムには getItemLayout を指定します:(data, index) => ({ length: 80, offset: 80 * index, index })
FlashListFlatList も優れていますが、大きなリストには FlashList がさらに適しています@shopify/flash-list はドロップインで置き換えられ、リサイクル方式のアーキテクチャを採用しています
リスト内の大きな画像フル解像度の画像はメインスレッドでデコードされますexpo-image をプレースホルダーとトランジションとともに使用し、サイズを指定します
FlatList のチェックリスト

すべての FlatList に次の項目を設定してください:

<FlatList
  data={items}
  keyExtractor={(item) => item.id}
  renderItem={renderItem}           // Memoised component
  getItemLayout={getItemLayout}     // If items are fixed height
  initialNumToRender={10}           // Don't render 100 items on mount
  maxToRenderPerBatch={10}          // Batch size for off-screen rendering
  windowSize={5}                    // How many screens to keep in memory
  removeClippedSubviews={true}      // Unmount off-screen items (Android)
/>

2. アニメーション(HIGH)

ネイティブアニメーションは UI スレッドで実行されます。JS アニメーションは JS スレッドをブロックし、カクつきを引き起こします。

パターン問題解決策
複雑なアニメーションに Animated API を使用Animated は JS スレッドで実行され、操作を妨げますUI スレッドで実行される react-native-reanimated を使用します
レイアウトアニメーションアイテムがトランジションなしで表示・非表示になりますLayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
共有要素のトランジション画面間を移動すると、要素が瞬間移動しますreact-native-reanimated の共有トランジション、または expo-router の共有要素を使用します
ジェスチャー + アニメーションドラッグやスワイプが遅れて感じられますreact-native-gesture-handler と reanimated のワークレットを組み合わせます。すべて UI スレッドで実行されます
レイアウトの測定onLayout の発火が遅く、ちらつきが発生します共有値と useAnimatedStyle を使用して、即座に反応させます
Reanimated の基本
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';

function AnimatedBox() {
  const offset = useSharedValue(0);
  const style = useAnimatedStyle(() => ({
    transform: [{ translateX: withSpring(offset.value) }],
  }));

  return (
    <GestureDetector gesture={panGesture}>
      <Animated.View style={[styles.box, style]} />
    </GestureDetector>
  );
}

3. ナビゲーション(HIGH)

パターン問題解決策
Expo RouterReact Native 向けのファイルベースルーティング(Next.js のような方式)です_layout.tsx ファイルを含む app/ ディレクトリを使用します。新しい Expo プロジェクトで推奨されます
スタック内の負荷の高い画面すべての画面がスタック内でマウントされたままになります表示されていないときに保持する必要がない画面には unmountOnBlur: true を使用します
ディープリンクアプリが URL に反応しませんExpo Router では自動的に処理されます。Bare RN の場合は Linking API の設定が必要です
タブバッジの更新タブにフォーカスがあってもバッジの数が更新されませんuseIsFocused() を使用するか、フォーカス時に再取得します:useFocusEffect(useCallback(...))
ナビゲーション状態の永続化アプリがバックグラウンドに移行したり終了したりすると、位置が失われますAsyncStorage と組み合わせて onStateChange と initialState を使用します
Expo Router の構成
app/
├── _layout.tsx          # Root layout (tab navigator)
├── index.tsx            # Home tab
├── (tabs)/
│   ├── _layout.tsx      # Tab bar config
│   ├── home.tsx
│   ├── search.tsx
│   └── profile.tsx
├── [id].tsx             # Dynamic route
└── modal.tsx            # Modal route

4. UI パターン(高)

パターン問題解決策
セーフエリアノッチやホームインジケーターの下にコンテンツが表示されますreact-native-safe-area-context の <SafeAreaView> または useSafeAreaInsets()
キーボード回避フォームのフィールドがキーボードに隠れます<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
プラットフォーム固有のコードiOS と Android で異なる動作が必要ですPlatform.select({ ios: ..., android: ... }) または .ios.tsx/.android.tsx ファイル
ステータスバーステータスバーがコンテンツに重なる、または色が正しくありませんルートレイアウトで expo-status-bar の <StatusBar style="auto" /> を使用します
タッチ領域ボタンが小さすぎてタップできません最小サイズは 44x44pt です。hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} を使用します
触覚フィードバックタップしても反応が感じられませんexpo-haptics を使用し、重要なアクションで Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light) を呼び出します

5. 画像とメディア(中)

パターン問題解決策
画像コンポーネントreact-native の <Image> は基本的な機能しかありませんexpo-image を使用します。キャッシュ、プレースホルダー、トランジション、blurhash に対応しています
寸法が指定されていないリモート画像画像の読み込み時にレイアウトがずれます必ず width と height を指定するか、aspectRatio を使用します
大きな画像Android で OOM クラッシュが発生しますサーバー側でサイズを変更するか、メモリを適切に処理する expo-image を使用します
SVGSVG は標準ではサポートされていませんSVG のインポートには react-native-svg と react-native-svg-transformer を使用します
動画動画の再生expo-av または expo-video(新しい API)を使用します

6. 状態とデータ(中)

パターン問題解決策
複雑なデータに AsyncStorage を使用読み込みのたびに JSON のパース/文字列化が発生しますMMKV(react-native-mmkv)を使用します。AsyncStorage より 30 倍高速です
グローバル状態単純な状態管理に Redux/MobX のボイラープレートが必要ですZustand は最小限の実装で、React Native との相性も優れています
サーバー状態フェッチ、読み込み中、エラー、キャッシュを手動で管理する必要がありますTanStack Query は Web 版と同様に React Native でも動作します
オフラインファーストネットワークがないとアプリを使えませんTanStack Query の persistQueryClient と MMKV を組み合わせるか、複雑なオフライン処理には WatermelonDB を使用します
深い階層の状態更新ネストされたオブジェクトでスプレッド演算子が煩雑になりますZustand 経由で Immer を使用します:set(produce(state => { state.user.name = 'new' }))

7. Expo ワークフロー(中)

パターン使用する場面方法
開発ビルドネイティブモジュールが必要な場合npx expo run:ios または eas build --profile development
Expo Goネイティブモジュールを使わない素早いプロトタイピングnpx expo start を実行し、QR コードをスキャンします
EAS BuildCI/CD、アプリストア向けビルドeas build --platform ios --profile production
EAS Updateアプリストアの審査なしでホットフィックスを適用する場合eas update --branch production --message "Fix bug"
設定プラグインeject せずにネイティブ設定を変更する場合expo-build-properties またはカスタム設定プラグインを使い、app.config.ts を設定します
環境変数ビルドごとに異なる設定を使う場合eas.json のビルドプロファイルと expo-constants を使用します
新しいプロジェクトのセットアップ
npx create-expo-app my-app --template tabs
cd my-app
npx expo install expo-image react-native-reanimated react-native-gesture-handler react-native-safe-area-context

8. テスト(低〜中)

ツール用途セットアップ
Jest単体テスト、フックのテストExpo にデフォルトで含まれています
React Native Testing Libraryコンポーネントのテスト@testing-library/react-native
Detox実機/シミュレーターでの E2E テストdetox — Wix のテストフレームワーク
MaestroYAML フローによる E2E テストmaestro test flow.yaml — Detox より簡単です

よくある落とし穴

落とし穴対処方法
Metro バンドラーのキャッシュnpx expo start --clear
Pod のインストールに関する問題(iOS)cd ios && pod install --repo-update
Reanimated が動作しないルートで最初にインポートする必要があります:import 'react-native-reanimated'
Expo SDK のアップグレードSDK のバージョンを更新した後、npx expo install --fix を実行します
Android のビルドに失敗するメモリ設定を gradle.properties で確認します:org.gradle.jvmargs=-Xmx4g
iOS シミュレーターの動作が遅いパフォーマンステストには実機を使用してください。シミュレーターでは実際のパフォーマンスを再現できません

コメント