◉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-29初級

Rork アプリのエラーハンドリングとクラッシュ対策入門 — 安定したアプリを作るための基本テクニック

Rorkで開発したアプリを安定させるエラーハンドリング入門です。try-catchの基本、UIのクラッシュを防ぐError Boundary、オフライン対策とリトライを含むネットワークエラー処理、入力バリデーション、問題を素早く特定するデバッグ手法まで初心者向けに解説します。

Rork585エラーハンドリング5デバッグ22クラッシュ対策4React Native239アプリ開発76

取り組みの背景 — なぜエラーハンドリングが重要なのか

アプリ開発を始めたばかりの頃は、新しい機能を追加することに集中しがちです。しかし、ユーザーにとって本当に大切なのは「アプリが安定して動く」こと。どんなに魅力的な機能があっても、頻繁にクラッシュするアプリは使い続けてもらえません。

Rork を使ったアプリ開発では、AI がコードを自動生成してくれるため、基本的なエラー処理が見落とされることがあります。ここではRork アプリの安定性を高めるためのエラーハンドリングとクラッシュ対策の基本を、初心者の方にもわかりやすく解説します。

この記事を読むことで、以下のスキルが身につきます。

  • JavaScript / React Native の基本的なエラーハンドリング手法
  • API通信時のエラー処理パターン
  • クラッシュを未然に防ぐための設計の考え方
  • 問題が起きたときのデバッグ手法

try-catch — エラーを安全にキャッチする基本構文

エラーハンドリングの最も基本的な手法が try-catch です。処理が失敗する可能性のあるコードを try ブロックで囲み、エラーが発生した場合に catch ブロックで安全に処理します。

// Rork アプリでの基本的な try-catch パターン
const fetchUserData = async (userId) => {
  try {
    const response = await fetch(`https://api.example.com/users/${userId}`);
 
    // HTTP ステータスコードのチェック
    if (!response.ok) {
      throw new Error(`サーバーエラー: ${response.status}`);
    }
 
    const data = await response.json();
    return data;
  } catch (error) {
    // エラーの種類に応じた処理
    if (error.message.includes('Network request failed')) {
      console.warn('ネットワーク接続を確認してください');
    } else {
      console.error('データ取得に失敗しました:', error.message);
    }
    return null; // フォールバック値を返す
  }
};
 
// 使用例
// 期待する出力(正常時): ユーザーデータオブジェクト
// 期待する出力(エラー時): null(+ コンソールにエラーメッセージ)

ここで大切なのは、catch ブロック内でただエラーを握りつぶすのではなく、ユーザーに適切なフィードバックを返すことです。「何かがうまくいかなかった」ことをユーザーに伝え、次に取るべきアクション(リトライ、ネットワーク確認など)を示しましょう。

Error Boundary — UIのクラッシュを防ぐ安全網

React Native アプリでは、レンダリング中にエラーが発生するとアプリ全体がクラッシュしてしまいます。これを防ぐのが Error Boundary(エラー境界)です。

Error Boundary は、子コンポーネントのレンダリングエラーをキャッチし、クラッシュの代わりにフォールバック UI を表示する仕組みです。

// ErrorBoundary コンポーネントの実装
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
 
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
 
  static getDerivedStateFromError(error) {
    // エラー発生時にフォールバック UI を表示するためステートを更新
    return { hasError: true, error };
  }
 
  componentDidCatch(error, errorInfo) {
    // エラーログをサービスに送信(本番環境で重要)
    console.error('Error Boundary caught:', error, errorInfo);
  }
 
  handleRetry = () => {
    this.setState({ hasError: false, error: null });
  };
 
  render() {
    if (this.state.hasError) {
      return (
        <View style={styles.container}>
          <Text style={styles.title}>問題が発生しました</Text>
          <Text style={styles.message}>
            申し訳ございません。画面の読み込み中にエラーが発生しました。
          </Text>
          <TouchableOpacity style={styles.button} onPress={this.handleRetry}>
            <Text style={styles.buttonText}>もう一度試す</Text>
          </TouchableOpacity>
        </View>
      );
    }
    return this.props.children;
  }
}
 
// 期待する動作:
// 子コンポーネントでエラー → フォールバック UI 表示
// 「もう一度試す」タップ → 子コンポーネント再レンダリング

Error Boundary の配置は戦略的に行いましょう。アプリ全体を1つの Error Boundary で囲むだけでなく、画面ごとや重要なセクションごとに配置することで、エラーの影響範囲を最小限に抑えられます。

ネットワークエラーへの対応 — オフライン対策とリトライ

モバイルアプリでは、ネットワーク接続が不安定になることは日常的に起こります。電波の弱い場所、Wi-Fi の切り替え時、機内モードなど、さまざまな場面でネットワークエラーが発生します。

Rork アプリでネットワーク通信を行う際は、以下の3つのポイントを意識しましょう。

接続状態の確認

import NetInfo from '@react-native-community/netinfo';
 
// ネットワーク状態を監視するカスタムフック
const useNetworkStatus = () => {
  const [isConnected, setIsConnected] = React.useState(true);
 
  React.useEffect(() => {
    const unsubscribe = NetInfo.addEventListener((state) => {
      setIsConnected(state.isConnected);
    });
    return () => unsubscribe();
  }, []);
 
  return isConnected;
};
 
// 使用例
const MyScreen = () => {
  const isConnected = useNetworkStatus();
 
  if (!isConnected) {
    return <OfflineBanner message="インターネット接続がありません" />;
  }
 
  return <MainContent />;
};

タイムアウトの設定

API リクエストにはタイムアウトを設定し、いつまでもレスポンスを待ち続けることがないようにします。

// タイムアウト付き fetch の実装
const fetchWithTimeout = async (url, options = {}, timeout = 10000) => {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);
 
  try {
    const response = await fetch(url, {
      ...options,
      signal: controller.signal,
    });
    clearTimeout(timeoutId);
    return response;
  } catch (error) {
    clearTimeout(timeoutId);
    if (error.name === 'AbortError') {
      throw new Error('リクエストがタイムアウトしました');
    }
    throw error;
  }
};
 
// 期待する出力(タイムアウト時): Error: リクエストがタイムアウトしました

リトライ機構

一時的なエラーに対しては、自動リトライを実装することでユーザー体験を改善できます。

// 指数バックオフ付きリトライ関数
const fetchWithRetry = async (url, options = {}, maxRetries = 3) => {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetchWithTimeout(url, options);
      if (response.ok) return response;
 
      // 5xx エラーはリトライ対象
      if (response.status >= 500) {
        throw new Error(`Server error: ${response.status}`);
      }
      // 4xx エラーはリトライしない
      return response;
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;
      // 指数バックオフ: 1秒, 2秒, 4秒...
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise((resolve) => setTimeout(resolve, delay));
    }
  }
};

ネットワークエラー処理の実践的なパターンについては、Rork アプリの起動クラッシュ・白画面 完全解決ガイドでも詳しく解説しています。

入力バリデーション — ユーザー入力によるエラーを防ぐ

ユーザーからの入力は、常に「予期しない値が来る可能性がある」と考えて処理しましょう。フォーム入力、検索クエリ、設定値など、あらゆる入力をバリデーションすることでクラッシュを防げます。

// 入力バリデーションのユーティリティ関数
const validateInput = {
  // メールアドレスの形式チェック
  isValidEmail: (email) => {
    if (!email || typeof email !== 'string') return false;
    const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return pattern.test(email.trim());
  },
 
  // 数値の範囲チェック
  isInRange: (value, min, max) => {
    const num = Number(value);
    return !isNaN(num) && num >= min && num <= max;
  },
 
  // 文字列の長さチェック
  isValidLength: (text, minLen, maxLen) => {
    if (!text || typeof text !== 'string') return false;
    const trimmed = text.trim();
    return trimmed.length >= minLen && trimmed.length <= maxLen;
  },
};
 
// フォーム送信時の使用例
const handleSubmit = (formData) => {
  const errors = [];
 
  if (!validateInput.isValidEmail(formData.email)) {
    errors.push('正しいメールアドレスを入力してください');
  }
  if (!validateInput.isValidLength(formData.name, 1, 50)) {
    errors.push('名前は1〜50文字で入力してください');
  }
 
  if (errors.length > 0) {
    // エラーメッセージを表示
    Alert.alert('入力エラー', errors.join('\n'));
    return;
  }
 
  // バリデーション通過後の処理
  submitData(formData);
};

バリデーションは「クライアント側」と「サーバー側」の両方で実施するのが鉄則です。クライアント側のバリデーションはユーザー体験の向上のため、サーバー側はセキュリティのためと考えましょう。

デバッグの基本テクニック — 問題を素早く特定する方法

エラーが発生したとき、素早く原因を特定する力はアプリ開発において非常に重要です。Rork アプリでのデバッグに役立つ基本テクニックを紹介します。

console メソッドの使い分け

// console.log — 一般的な情報出力
console.log('ユーザーデータ:', userData);
 
// console.warn — 警告(黄色表示)
console.warn('APIレスポンスに予期しないフィールドがあります');
 
// console.error — エラー(赤色表示)
console.error('認証トークンの取得に失敗:', error);
 
// console.table — オブジェクト/配列を表形式で表示
console.table([
  { name: 'API呼び出し', duration: '120ms', status: 'success' },
  { name: 'DB書き込み', duration: '45ms', status: 'success' },
]);
 
// console.time / timeEnd — 処理時間の計測
console.time('データ取得');
const data = await fetchUserData();
console.timeEnd('データ取得');
// 期待する出力: データ取得: 235.42ms

条件付きデバッグログ

本番環境ではデバッグログを出力しないよう、環境に応じた制御を入れましょう。

// デバッグユーティリティ
const DEBUG = __DEV__; // React Native の開発モードフラグ
 
const logger = {
  debug: (...args) => {
    if (DEBUG) console.log('[DEBUG]', ...args);
  },
  warn: (...args) => {
    console.warn('[WARN]', ...args);
  },
  error: (...args) => {
    console.error('[ERROR]', ...args);
    // 本番環境ではエラーレポートサービスに送信
    if (!DEBUG) {
      // reportError(args);
    }
  },
};
 
// 使用例
logger.debug('現在のステート:', state);  // 開発時のみ出力
logger.error('決済処理でエラー:', error); // 常に出力 + 本番ではレポート送信

エラー解析と本番環境での監視をさらに深く学びたい方には、Rork Maxアプリのクラッシュ解析・監視完全ガイドで Sentry や Firebase Crashlytics を活用した実践的な監視手法を詳しく解説しています。

まとめ

エラーハンドリングとクラッシュ対策は、アプリの品質を左右する基盤となるスキルです。この記事で紹介した基本テクニックを実践するだけでも、アプリの安定性は大きく向上します。

まずは try-catch による基本的なエラーキャッチから始め、Error Boundary の配置、ネットワークエラーへの対応と段階的に取り組んでみてください。完璧を目指す必要はありません。「エラーが起きてもアプリがクラッシュしない」状態を作ることが最初のゴールです。

より高度なエラーハンドリングのパターンや本番監視体制について学びたい方には、Rork Max エラーハンドリング・デバッグ・本番監視の実践パターンがおすすめです。

シェア

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

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

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

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

関連記事

⬡ 開発ツール2026-06-22
壊れたキャッシュで毎回起動時に落ちるアプリ——ユーザーが自力で抜け出せる「セーフモード起動」を設計する
永続化したキャッシュが壊れて起動のたびに同じ場所で落ちると、ユーザーには再インストールしか残りません。アプリ自身が早期クラッシュの連続を数え、対話可能になって初めて起動を確定し、危険な状態だけを段階的にリセットするセーフモードを、Expo(React Native)の実装で設計します。
⬡ 開発ツール2026-09-04
EAS の secret は「アプリに入れない」設定ではありません — 接頭辞と可視性を別々に決める
EXPO_PUBLIC_ の接頭辞は成果物に入るかを決め、EAS の可視性は誰が読めるかを決めます。二つを重ねたときに OTA 更新でだけ値が消える筋道と、出荷前に自分の手で確かめる手順をまとめました。
⬡ 開発ツール2026-08-22
一括置換は全ファイル成功しました。壊れたのは、消さなかった行のほうです
生成コードに一括置換をかけると、一致した行ではなく隣の行が壊れます。運用中のプロジェクトで実際に起きた破損と、置換の不変条件を検査する20行のガードスクリプトをまとめました。