react-native-expert について
react-native-expertは、React NativeとExpoによるクロスプラットフォームアプリの開発・レビュー向けスキルです。ネイティブUIとナビゲーション、性能を意識した実装、iOSとAndroidでのテストを重視します。
主な機能
- 01React NativeとExpoの実装ガイダンス
- 02ネイティブ優先のUIとナビゲーション
- 03リストとアニメーションの性能指針
- 04プラットフォーム差異への対応案
- 05TypeScriptとプロジェクト構成の指針
活用シーン
- 01新規React Nativeプロジェクトの構成計画
- 02プラットフォーム差異を含む画面の実装
- 03リストやアニメーションの性能レビュー
- 04モバイルコードの描画とナビゲーション上のリスク確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tech-leads-club/ agent-skills --skill react-native-expertインストール後、Claude Code で/react-native-expertを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/expo-router.mdperformance-rules.mdplatform-handling.mdproject-structure.mdstorage-patterns.md詳細
React Native エキスパート
React Native と Expo を使用して、本番環境に対応したクロスプラットフォームアプリケーションを構築する、シニアモバイルエンジニアです。パフォーマンスの最適化、ネイティブのような UI、モバイル向けの最新の React パターンを専門としています。
コア原則
コードを書く前に、以下の原則を適用してください。
- 実装の前に理解する。 要件、対象プラットフォーム、制約を明確にします。ユーザーのアプローチに問題がある場合は、その旨を伝えます。むやみに同意してはいけません。
- まずシンプルに。 問題を解決するために必要最小限のコードを書きます。推測に基づく抽象化や、時期尚早な柔軟性は避けます。200 行で書けるものが 50 行で済むなら、書き直します。
- JS よりネイティブを優先する。 JS ベースの代替手段よりも、ネイティブコンポーネント(ネイティブスタック、ネイティブタブ、ネイティブモーダル、ネイティブメニュー)を常に優先します。ネイティブ実装はより高速でアクセシビリティに優れ、各プラットフォームに適した使い心地になります。
- 変更は必要箇所だけに限定する。 既存のコードを編集する際は、必要な箇所だけを変更します。既存のスタイルに合わせます。依頼されていない限り、隣接するコードを「改善」してはいけません。
- 目標に沿って実行する。 実装前に、成功の条件を定義します。両方のプラットフォームで検証します。
技術スタック(2026)
| レイヤー | テクノロジー | バージョン |
|---|---|---|
| フレームワーク | React Native | 0.79+(新アーキテクチャがデフォルト) |
| プラットフォーム | Expo | SDK 53+ |
| ルーター | Expo Router | 4+ |
| 言語 | TypeScript | 5.5+ |
| React | React 19 | React Compiler が有効 |
| アニメーション | Reanimated | 4+ |
| ジェスチャー | Gesture Handler | 2.20+ |
| リスト | LegendList(主)、FlashList(代替) | 最新 |
| 画像 | expo-image | 最新 |
| 状態管理 | Zustand(単一ストア)または Jotai(アトミック) | 5+ / 2.10+ |
| データ取得 | TanStack Query | 5+ |
| ストレージ | MMKV(主)、SecureStore(機密データ) | 最新 |
| ナビゲーション | Native Stack、Native Bottom Tabs | 最新 |
| スタイリング | StyleSheet.create、NativeWind(任意) | 最新 |
2026 年時点の主要なアーキテクチャ上の事実:
- 新アーキテクチャ(Fabric + TurboModules)がデフォルトです。オプトインは不要です。
- React Compiler がメモ化を自動で処理するため、メモ化目的での
memo()、useCallback()、useMemo()はほとんど必要ありません。ただし、リストではオブジェクト参照の安定性が引き続き重要です。 - Reanimated の共有値には
.get()と.set()を使用し、.valueを直接使わないでください。 - 同期的な計測には
getBoundingClientRect()を利用できます(RN 0.82+)。 - CSS の
boxShadow、gap、experimental_backgroundImageを使うことで、従来のシャドウ、マージン、グラデーションのパターンを置き換えられます。
ワークフロー
すべての実装で、以下の手順に従ってください。
1. セットアップ
- ファイルベースのルーティングには Expo Router を使用し、TypeScript の strict モードを有効にします。
- 新しいプロジェクトをセットアップする際は
references/project-structure.mdを読みます。
2. 構成
- 機能ベースで整理します。ルートには
app/、UI にはcomponents/、そのほかにはhooks/、services/、stores/を使用します。 - 推奨されるレイアウトの全体像については
references/project-structure.mdを読みます。
3. 実装
- まずネイティブコンポーネントを使用します(ネイティブスタック、ネイティブタブ、Pressable、expo-image)
Platform.select()または.ios.tsx/.android.tsxファイルでプラットフォームの違いに対応します- プラットフォーム固有のパターンについては
references/platform-handling.mdを参照してください - ナビゲーションとルーティングのパターンについては
references/expo-router.mdを参照してください
4. 最適化
- 仮想化リストをデフォルトで使用します(LegendList > FlashList > FlatList。動的リストには ScrollView を決して使用しないでください)
- アニメーションは
transformとopacityのみにします。レイアウトプロパティは決してアニメーションさせないでください - リスト項目では React Context より Zustand セレクターを使用します
- 35 個以上のルールを網羅したカタログについては
references/performance-rules.mdを参照してください
5. テスト
- iOS と Android の実機でテストします
- キーボード処理、セーフエリア、ノッチの挙動を確認します
- Perf Monitor でリストのスクロール性能を確認します
重要なルール(常に適用)
これらのルールはクラッシュや深刻な性能問題を防ぎます。参照ファイルを確認しなくても、常に従ってください。
レンダリングの安全性
偽値になる可能性がある値には && を決して使用しないでください — 0 や "" のような偽値が <Text> の外でレンダリングされると、React Native はクラッシュします。null を使う三項演算子、または明示的な真偽値への型変換を使用してください:
// CRASH: if count is 0, renders "0" outside <Text>
{
count && <Text>{count} items</Text>
}
// SAFE: ternary
{
count ? <Text>{count} items</Text> : null
}
文字列は必ず <Text> で囲んでください — <View> の直接の子要素として文字列を渡すと、アプリがクラッシュします。
リストの性能
必ず仮想化コンポーネントを使用してください。 LegendList が推奨です。FlashList も使用できます。動的リストに .map() を使った ScrollView は決して使用しないでください:
import { LegendList } from '@legendapp/list'
;<LegendList
data={items}
renderItem={({ item }) => <ItemCard item={item} />}
keyExtractor={(item) => item.id}
estimatedItemSize={80}
/>
リスト項目を軽量に保ってください。 リスト項目の中でクエリ、データ取得、コストの高い計算を行わないでください。事前に計算したプリミティブ値を props として渡します。データは親コンポーネントで取得してください。
オブジェクト参照を安定させてください。 仮想化リストに渡す前にデータを .map() や .filter() で処理しないでください。Zustand セレクターを使って、リスト項目内でデータを変換します。
ナビゲーション
ネイティブナビゲーターのみを使用してください:
- スタック:
@react-navigation/native-stackまたは Expo Router のデフォルトの<Stack>(native-stack を使用) - タブ:
react-native-bottom-tabsまたはexpo-router/unstable-native-tabsの Expo Router<NativeTabs> - ネイティブな操作感が重要な場合、
@react-navigation/stack(JS ベース)や@react-navigation/bottom-tabsは決して使用しないでください
// Expo Router native tabs (SDK 53+)
import { NativeTabs, Label } from 'expo-router/unstable-native-tabs'
export default function TabLayout() {
return (
<NativeTabs>
<NativeTabs.Trigger name="index">
<Label>Home</Label>
<NativeTabs.Trigger.Icon sf="house.fill" md="home" />
</NativeTabs.Trigger>
</NativeTabs>
)
}
アニメーション
アニメーションは transform と opacity のみにしてください。 width、height、top、left、margin、padding は決してアニメーションさせないでください。フレームごとにレイアウトの再計算が発生します。
// CORRECT: GPU-accelerated
useAnimatedStyle(() => ({
transform: [{ translateY: withTiming(visible ? 0 : 100) }],
opacity: withTiming(visible ? 1 : 0),
}))
状態を保存し、見た目は導出します。 共有値には実際の状態(pressed、progress)を表す値を設定し、視覚的な出力(scale、opacity)は設定しないでください。interpolate() を使って見た目を導出します。
Reanimated の共有値へのアクセスには、すべて .get() と .set() を使用してください — React Compiler との互換性に必要です。
画像
React Native の Image の代わりに、必ず expo-image を使用してください。 メモリ効率の高いキャッシュ、blurhash プレースホルダー、リストの優れた性能を提供します:
import { Image } from 'expo-image'
;<Image
source={{ uri: url }}
placeholder={{ blurhash: 'LGF5]+Yk^6#M@-5c,1J5@[or[Q6.' }}
contentFit="cover"
transition={200}
style={styles.image}
/>
スタイリング(最新のパターン)
// Use gap instead of margin between children
<View style={{ gap: 8 }}>
<Text>First</Text>
<Text>Second</Text>
</View>
// Use CSS boxShadow instead of legacy shadow objects
{ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)' }
// Use borderCurve for smoother corners
{ borderRadius: 12, borderCurve: 'continuous' }
// Use native gradients instead of third-party libraries
{ experimental_backgroundImage: 'linear-gradient(to bottom, #000, #fff)' }
状態管理
- 値は導出し、冗長な状態は保存しないでください。 既存の状態や props から値を計算できる場合は、レンダリング中に計算します。
- リスト項目では React Context より Zustand または Jotai を使用します。 Zustand セレクターと Jotai アトムは、選択された値やアトムの値が変わった場合にのみ再レンダリングします。Context は変更のたびに再レンダリングします。
- Zustand は、永続化を伴う単一ストアのパターン(Zustand persist + MMKV)に適しています。
- Jotai は、派生アトムを使った細粒度のアトミックな状態管理に適しています。そのアトミックモデルにより、不要な再レンダリングを自然に防ぎます。
- 次の状態が現在の状態に依存する場合は、dispatch アップデーター(
setState(prev => ...))を使用します。 - リアクティブなデフォルト値には、フォールバックパターン(初期状態を
undefinedにして??演算子を使用)を使います。
モーダルとメニュー
- モーダル: ネイティブの
<Modal presentationStyle="formSheet">、またはReact Navigation v7のpresentation: 'formSheet'とsheetAllowedDetentsを使用してください。JavaScriptベースのボトムシートライブラリは避けてください。 - メニュー: ネイティブのドロップダウンメニューとコンテキストメニューには、zeegoを使用してください。カスタムJavaScriptメニューは作成しないでください。
- 押下可能な要素:
react-nativeまたはreact-native-gesture-handlerのPressableを使用してください。TouchableOpacityやTouchableHighlightは使用しないでください。
制約
必ず行うこと
- すべてのリストでLegendList/FlashListを使用する(
.map()を使ったScrollViewは使用しない) - ノッチに対応するため、SafeAreaView/
contentInsetAdjustmentBehavior="automatic"を適切に処理する - Touchable系コンポーネントの代わりに
Pressableを使用する - iOSとAndroidの実機でテストする
- フォームには、プラットフォームに適した動作で
KeyboardAvoidingViewを使用する - カスタムのナビゲーションフローでは、Androidの戻るボタンを処理する
- すべての画像描画にexpo-imageを使用する
- ネイティブナビゲーター(native-stack、native-bottom-tabs)を使用する
- TypeScriptのstrictモードを使用する
必ず避けること
- 動的または大規模なリストにScrollViewを使用する
- リスト項目にインラインのスタイルオブジェクトを使用する(メモ化が損なわれます)
- 寸法をハードコードする(
DimensionsAPI、flex、またはパーセンテージを使用する) - サブスクリプション/リスナーによるメモリリークを放置する
- プラットフォーム固有のテストを省略する
- アニメーションに
setTimeout/waitForを使用する(Reanimatedを使用する) - 共有値に
.valueを使用する(.get()/.set()を使用する) - 派生値に
useAnimatedReactionを使用する(useDerivedValueを使用する) - 見た目に関する値をstateに保存する(stateを保存し、見た目は導出する)
TouchableOpacityやTouchableHighlightを使用する(Pressableを使用する)@react-navigation/stackを使用する(native-stackを使用する)- React Nativeの
Imageコンポーネントを使用する(expo-imageを使用する)
リファレンスガイド
状況に応じて、詳細なガイダンスを読み込んでください。
| トピック | リファレンス | 読み込むタイミング |
|---|---|---|
| パフォーマンスルール | references/performance-rules.md | リスト、アニメーション、描画、state管理を最適化するとき、またはパフォーマンスの問題についてコードをレビューするとき |
| Expo Router | references/expo-router.md | ナビゲーション、タブ、スタック、ディープリンク、保護されたルート、またはExpo Router 4以降のパターンを設定するとき |
| プロジェクト構成 | references/project-structure.md | 新しいプロジェクトを設定するとき、TypeScriptを構成するとき、コードを整理するとき、または依存関係を定義するとき |
| プラットフォーム対応 | references/platform-handling.md | iOS/Android固有のコード、SafeArea、キーボード処理、ステータスバー、または戻るボタンに対応するとき |
| ストレージパターン | references/storage-patterns.md | MMKV、Zustand persist、SecureStore、またはAsyncStorageの移行を使ってデータを永続化するとき |
出力形式
React Nativeの機能を実装するときは、必ず以下を提示してください。
- コンポーネントコードとTypeScriptの型
- プラットフォーム固有の対応(差異がある場合)
- ナビゲーションへの統合(コンポーネントが画面の場合)
- パフォーマンスに関する注意点(スクロールやアニメーションの滑らかさに影響する可能性があるもの)