◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/開発ツール
⬡ 開発ツール/2026-03-30中級

Rork で出る React Native / Expo ランタイムエラーを切り分けて直す

Rork が生成する React Native + Expo ベースのアプリで発生する典型的なランタイムエラーの完全な解決ガイド。TypeError、Hooks ルール違反、モジュール互換性問題を実例とコード例で解説。

React Native239Expo219ランタイムエラーtroubleshooting26

Rork アプリが React Native / Expo ベースである理由

Rork が生成するモバイルアプリは、内部的に React Native + Expo で構築されています。このため、React Native 固有のランタイムエラーが発生することがあります。これらのエラーは一度理解すれば、以降のアプリ開発で繰り返し遭遇する同じパターンなので、今のうちに解決方法を習得しておく点が肝心です。


よくあるランタイムエラー TOP 5

1. TypeError: undefined is not an object

症状: アプリが起動直後にクラッシュし、コンソールに TypeError: undefined is not an object と表示されます。

原因: State(状態)の初期化を忘れているケースが大半です。

// ❌ 間違い: state の初期値がない
import { useState } from "react";
import { View, Text, FlatList } from "react-native";
 
export default function ProductList() {
  const [products, setProducts] = useState(); // undefined として初期化される
 
  return (
    <FlatList
      data={products}  // undefined.map() を呼ぼうとしてエラーになる
      renderItem={({ item }) => <Text>{item.name}</Text>}
      keyExtractor={(item) => item.id}
    />
  );
}
 
// ✅ 正しい: 空配列で初期化
export default function ProductList() {
  const [products, setProducts] = useState([]); // 空配列で初期化
 
  return (
    <FlatList
      data={products}  // 安全に反復できる
      renderItem={({ item }) => <Text>{item.name}</Text>}
      keyExtractor={(item) => item.id}
    />
  );
}

解決方法:

  • useState(undefined) ではなく、適切な初期値(空配列 []、デフォルトオブジェクト {}、など)を指定する
  • データ取得完了まで UI を条件付きレンダリングする(if (!data) return <Loading />)

2. Invariant Violation: Text strings must be rendered within a component

症状: コンソールに Invariant Violation: Text strings must be rendered within a <Text> component と表示され、赤い画面が出現します。

原因: React Native では、**テキスト文字列を直接 <View> に入れることができません。**すべてのテキストは <Text> コンポーネントでラップする必要があります。

// ❌ 間違い: テキストが <Text> にラップされていない
import { View } from "react-native";
 
export default function App() {
  return (
    <View>
      Hello World  {/* エラー! */}
    </View>
  );
}
 
// ✅ 正しい: <Text> コンポーネントを使う
import { View, Text } from "react-native";
 
export default function App() {
  return (
    <View>
      <Text>Hello World</Text>  {/* OK */}
    </View>
  );
}

解決方法:

  • すべてのテキスト文字列を <Text> でラップする
  • Rork の AI がこのパターンを検出できるよう、生成時に「React Native では Text コンポーネントを必ず使う」と指示する

3. Error: Rendered more hooks than during the previous render

症状: 画面を操作した後、コンソールに Error: Rendered more hooks than during the previous render が表示されます。

原因: React Hooks のルール違反です。以下の 2 つのパターンが典型的です:

  1. Hooks を条件分岐内で呼ぶ — if (condition) { useState(...) } はダメ
  2. ループ内で Hooks を呼ぶ — items.map(() => useEffect(...)) はダメ
// ❌ 間違い: 条件分岐内で useState を呼ぶ
import { useState } from "react";
import { View, Button, Text } from "react-native";
 
export default function Counter() {
  const [isEnabled, setIsEnabled] = useState(false);
 
  // ❌ このif文の中でuseStateを呼ぶと、条件によってHooks数が変わる
  if (isEnabled) {
    const [count, setCount] = useState(0);
  }
 
  return (
    <View>
      <Button title="Enable" onPress={() => setIsEnabled(!isEnabled)} />
    </View>
  );
}
 
// ✅ 正しい: すべての Hooks を関数のトップレベルで呼ぶ
export default function Counter() {
  const [isEnabled, setIsEnabled] = useState(false);
  const [count, setCount] = useState(0);  // トップレベルで呼ぶ
 
  return (
    <View>
      <Button title="Enable" onPress={() => setIsEnabled(!isEnabled)} />
      {isEnabled && <Text>Count: {count}</Text>}
    </View>
  );
}

解決方法:

  • Hooks ルール: Hooks は常にコンポーネントのトップレベルで呼ぶ(条件分岐やループの中では呼ばない)
  • useState / useEffect / useCallback など、すべての React Hooks が対象

4. Module not found / Cannot resolve module

症状: ビルド時またはアプリ起動時に Module not found: Can't resolve 'react-native-gesture-handler' のようなエラーが出る。

原因: インストールされていないパッケージを import したか、バージョンの不整合があります。

// ❌ インストールされていないパッケージをimport
import { GestureHandlerRootView } from "react-native-gesture-handler";  // インストールされていない
 
// ✅ 解決: npm install で追加
// $ npm install react-native-gesture-handler expo-gesture-handler

解決方法:

  • npm install {パッケージ名} でパッケージをインストール
  • 既にインストール済みなら npm install を実行して依存関係を再インストール
  • React Native / Expo のバージョンと互換性を確認(Expo の公式マトリックスを参照)
  • キャッシュをクリア: npx expo start --clear

5. White Screen of Death(白画面)— エラーバウンダリの活用

症状: アプリが起動しても何も表示されず、真っ白な画面が続く。コンソールにはエラーが出ていません。

原因: JavaScript エラーが発生しているが、エラー処理がされておらず、ユーザーに何も表示されていません。

解決方法: エラーバウンダリ(Error Boundary) コンポーネントを実装します。

// components/ErrorBoundary.tsx
import { View, Text, ScrollView } from "react-native";
import { ReactNode } from "react";
 
interface Props {
  children: ReactNode;
}
 
interface State {
  hasError: boolean;
  error: Error | null;
}
 
// エラーバウンダリ: 子コンポーネントで発生したエラーをキャッチして表示
export class ErrorBoundary extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
 
  static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error };
  }
 
  componentDidCatch(error: Error, errorInfo: any) {
    console.error("ErrorBoundary caught:", error, errorInfo);
  }
 
  render() {
    if (this.state.hasError) {
      return (
        <ScrollView contentContainerStyle={{ padding: 20, justifyContent: "center" }}>
          <Text style={{ fontSize: 18, fontWeight: "bold", color: "red", marginBottom: 10 }}>
            ⚠️ エラーが発生しました
          </Text>
          <Text style={{ fontSize: 14, color: "#666", marginBottom: 10 }}>
            {this.state.error?.message || "不明なエラー"}
          </Text>
          <Text style={{ fontSize: 12, color: "#999", fontFamily: "monospace" }}>
            {this.state.error?.stack}
          </Text>
        </ScrollView>
      );
    }
 
    return this.props.children;
  }
}

使い方:

// App.tsx
import { ErrorBoundary } from "./components/ErrorBoundary";
 
export default function App() {
  return (
    <ErrorBoundary>
      <YourMainApp />
    </ErrorBoundary>
  );
}

これでアプリが落ちるかわりに、エラー内容がユーザーに表示されます。


Rork のエラーログの読み方

Rork が生成するアプリでエラーが発生した場合、どこを見ればいいか を知ることが解決への第一歩です。

コンソールメッセージの階層

  • 青色メッセージ — デバッグ情報(無視してOK)
  • 黄色メッセージ — 警告(改善推奨)
  • 赤色メッセージ — エラー(修正必須)

エラーメッセージの読み方のコツ

Error: Invariant Violation: Text strings must be rendered within a <Text> component
  at node_modules/react-native/Libraries/Text/Text.js:100
  in MyComponent (at screens/HomeScreen.tsx:25)

この場合:

  • 何が起きた? → Text strings must be rendered within a Text component
  • どこで? → MyComponent
  • そのコンポーネントはどこ? → screens/HomeScreen.tsx の 25 行目

このように、エラーメッセージの上から順に読むことで、問題の箇所を特定できます。


Fix Now(自動デバッグ)機能の活用法

Rork では、エラー検出時に Fix Now 機能を使うことで、AI が自動的にコードを修正してくれます。

  1. エラーが表示されたら、スクリーンショットを撮ってコピー
  2. Rork チャットに貼り付けて「Fix Now」をクリック
  3. AI が修正コードを生成し、アプリに自動適用される

Fix Now が成功したら、修正内容を確認して理解することが大事。その修正パターンを次に生かせます。


Expo Go vs Development Build での違い

Expo Go(プレビューアプリ)と Development Build(カスタムビルド)では、発生するエラーが異なることがあります。

状況Expo GoDevelopment Build
ネイティブモジュール(カメラなど)未対応実行できない実行できる
パフォーマンス遅い(デバッグ情報込み)速い
デバッグ情報詳細少ない
本番環境に近いいいえはい

Expo Go でエラーが出ない = 本番環境でも安全 とは限りません。Development Build でテストしましょう。


Rork Companion アプリでの実機デバッグ

Rork Companion(Mac アプリ)を使うと、実機でのデバッグが格段に楽になります。

  • ライブログ表示 — デバイスのコンソール出力をリアルタイムで表示
  • ホットリロード — コード変更時に自動反映
  • デバイス選択 — 複数デバイスでの同時テスト

Rork Companion の詳しい使い方は「Rork Companion Mac App」を参照してください。


全体を振り返って

Rork で発生する React Native / Expo ランタイムエラーは、一度理由を理解すれば繰り返し学習できます。

  • State の初期化 — 必ず適切な初期値を指定する
  • Text コンポーネント — すべてのテキストをラップする
  • Hooks ルール — 条件分岐やループの外で呼ぶ
  • モジュール互換性 — バージョン確認と npm install を忘れずに
  • エラーバウンダリ — 白画面を防ぐために必須

こうしたパターンをマスターすると、Rork でのアプリ開発がスムーズになります。


参考資料

開発中に参考になる書籍:

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

⬡ 開発ツール2026-09-10
画面を暗くする機能を足したら、アプリを閉じたあとも iPhone が暗いままでした
expo-brightness の setBrightnessAsync は、Android では現在のアクティビティにだけ効き、iOS では端末の明るさそのものを変えます。戻す責任が片側にしかない理由と、AppState で後始末をするフックの実装をまとめました。
⬡ 開発ツール2026-09-04
EAS の secret は「アプリに入れない」設定ではありません — 接頭辞と可視性を別々に決める
EXPO_PUBLIC_ の接頭辞は成果物に入るかを決め、EAS の可視性は誰が読めるかを決めます。二つを重ねたときに OTA 更新でだけ値が消える筋道と、出荷前に自分の手で確かめる手順をまとめました。
⬡ 開発ツール2026-09-01
expo-paste-input で画像を貼り付けられる入力欄を作り、消える file:// を documents へ逃がす
チャット入力に画像やGIFを貼り付けられるようにする expo-paste-input の実装手順です。onPaste が返す file:// は一時ファイルで、送信までの間に消えることがあります。保存先を移す実装と、実機で確かめる順番をまとめました。