◉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-04-19初級

Rork で作ったアプリが固まる・操作に反応しなくなる問題:原因別の解決策まとめ

Rorkで作ったアプリが固まる、ボタンに反応しなくなる問題を4つの原因に分けて解決します。メインスレッドを塞ぐ重い処理、useEffectの依存配列による無限ループ、二重処理、FlatListのキー重複を診断し、AIに修正を依頼するコツも紹介します。

トラブルシューティング85デバッグ22パフォーマンス33React Native239フリーズ

画面は表示されています。でもボタンを押しても何も起きません——クラッシュしているわけでもなく、ローディングが続いているわけでもありません。そんな独特の「固まった」状態。Rork でアプリ開発をしていると、この状況に一度は遭遇するのではないでしょうか。

白い画面やクラッシュとは違って、フリーズは原因が見えにくいのが厄介なところです。私自身、初めてこの状態になったとき、何が起きているのかまったくわからずに30分ほど悩みました。ここではRork で生成されたコードでよく起こるフリーズのパターンを4つに整理して、それぞれの対処法をお伝えします。

よくある原因①:重い処理がメインスレッドをブロックしている

React Native のメインスレッドは UI の描画を担当しています。ここで重い処理が走ると、UI 全体が応答しなくなります。

Rork の AI が大量データのフィルター処理をメインスレッド上に書いてしまうことがあります。たとえばこういったコードです:

// ❌ 問題のある例:フィルター処理がメインスレッドをブロックする
const handleSearch = (query) => {
  const results = hugeDataArray.filter(item =>
    item.name.includes(query) &&
    item.description.includes(query) &&
    item.tags.some(tag => tag.includes(query))
  );
  setFilteredData(results);
};

データが数百件程度なら問題ないのですが、数千件を超えると UI が一瞬止まります。解決策は、処理を非同期にして UI スレッドを解放することです:

// ✅ 改善後:非同期で処理して UI をブロックしない
const handleSearch = useCallback(async (query) => {
  setLoading(true);
  // setTimeout(0) でメインスレッドを一瞬解放してから重い処理を実行
  await new Promise(resolve => setTimeout(resolve, 0));
  const results = hugeDataArray.filter(item =>
    item.name.includes(query)
  );
  setFilteredData(results);
  setLoading(false);
}, [hugeDataArray]);

Rork の AI にこの修正を依頼するときは、「handleSearch 関数を非同期にして、フィルタリング中はローディングインジケーターを表示するように修正してください」と指示すると、意図通りに書き直してくれます。

よくある原因②:useEffect の依存配列が原因の無限ループ

「画面を開いた瞬間は動くのに、しばらくすると固まる」という場合、useEffect の無限ループを疑ってください。API へのリクエストが止まらない状態になっていることがあります。

// ❌ 無限ループを引き起こす例
const [userData, setUserData] = useState(null);
 
useEffect(() => {
  fetchUserData().then(data => setUserData(data));
}, [userData]); // userData が更新されるたびに再実行される!

setUserData で状態が更新されると userData が変わり、再び useEffect が実行され……という無限ループです。UI が固まるだけでなく、API を無限に叩き続けるので、サーバー側にも影響が出ることがあります。

// ✅ 正しい依存配列
useEffect(() => {
  fetchUserData().then(data => setUserData(data));
}, []); // マウント時に一度だけ実行

Rork のプレビュー中に「ネットワークのリクエストがずっと飛び続けている」と感じたら、まず useEffect の依存配列を確認してみてください。

なお、React Native のコードを自分で読んで原因を追いたい場合は、Rork が生成したコードを読む:React Native の基礎が参考になります。

よくある原因③:ローディング状態の未実装による二重処理

ボタンを押したあと、API のレスポンスを待っている間もボタンが有効なままだと、連打による二重処理が発生します。これがフリーズに見えるケースがあります。

// ❌ ローディング制御がない例
const handleSubmit = async () => {
  const result = await submitForm(formData); // 処理中も何度でも押せてしまう
  navigate('/success');
};
// ✅ ローディング制御を追加した例
const [isSubmitting, setIsSubmitting] = useState(false);
 
const handleSubmit = async () => {
  if (isSubmitting) return; // 二重送信を防ぐ
  setIsSubmitting(true);
  try {
    const result = await submitForm(formData);
    navigate('/success');
  } catch (error) {
    console.error('送信エラー:', error);
    Alert.alert('エラー', '送信に失敗しました。もう一度お試しください。');
  } finally {
    setIsSubmitting(false); // 成功・失敗どちらでも必ずリセット
  }
};
 
// ボタン側
<TouchableOpacity
  onPress={handleSubmit}
  disabled={isSubmitting}
  style={[styles.button, isSubmitting && styles.buttonDisabled]}
>
  {isSubmitting
    ? <ActivityIndicator color="#fff" size="small" />
    : <Text style={styles.buttonText}>送信</Text>
  }
</TouchableOpacity>

Rork の AI にローディング状態の実装を依頼するときは、「送信ボタンを押したら処理が完了するまでボタンを無効化し、スピナーを表示してください。エラー時にはアラートを出してください」と具体的に書くと、より堅牢なコードが生成されます。

よくある原因④:FlatList のキーが重複している

大量のリスト表示で画面が固まる場合、FlatList の keyExtractor が原因のことがあります。

// ❌ キーが重複・未定義になる可能性がある例
<FlatList
  data={items}
  keyExtractor={(item) => item.id} // id が undefined だと "undefined" が大量に重複する
  renderItem={({ item }) => <ItemCard item={item} />}
/>

API から取得したデータに id が含まれていない場合、keyExtractor が "undefined" を返し続けます。React Native はキーの重複を検出するたびに内部でエラー処理を行うため、リストが長いほど動作が重くなります。

// ✅ 確実にユニークなキーを設定
<FlatList
  data={items}
  keyExtractor={(item, index) => item.id?.toString() ?? `item-${index}`}
  renderItem={({ item }) => <ItemCard item={item} />}
  // パフォーマンス改善オプション(長いリストに有効)
  removeClippedSubviews={true}
  maxToRenderPerBatch={10}
  windowSize={5}
  initialNumToRender={10}
/>

removeClippedSubviews={true} は、画面外のコンポーネントをメモリから解放してくれるオプションです。アイテム数が多いリストでは、これだけで体感速度が大きく改善することがあります。

Rork の AI に修正を依頼するときのコツ

フリーズの原因を特定したら、Rork のチャット欄で修正を依頼します。このとき、「どの画面で」「どの操作をしたとき」「どんな状態になるか」を具体的に伝えると、AI の修正精度が上がります。

たとえばこう伝えます:

「検索画面で文字を入力すると、500件のデータをフィルターする処理が走って画面が一瞬固まります。非同期処理に変更して、フィルタリング中はローディングインジケーターを表示するように修正してください。」

「フリーズするので直してください」と曖昧に伝えるよりも、原因の仮説を添えて依頼する方が、的確なコードが生成されます。React Native のパフォーマンス最適化全般については、Rork アプリのパフォーマンス最適化完全ガイドで詳しく解説しています。

コンソールログで原因を絞り込む

どのパターンか判断がつかない場合は、console.log() を疑わしい処理の前後に仕込んで、どこまで実行されているかを確認するのが最短の手段です。

const handlePress = async () => {
  console.log('ボタン押下: 処理開始');
  setIsLoading(true);
  console.log('ローディング状態: true');
  try {
    const data = await fetchData();
    console.log('データ取得成功:', data.length, '件');
    setItems(data);
  } catch (error) {
    console.error('エラー発生:', error.message);
  } finally {
    setIsLoading(false);
    console.log('ローディング状態: false');
  }
};

Rork Companion の開発者ツール(画面右下のアイコン)を開くと、これらのログをリアルタイムで確認できます。ログがどこで止まっているかを見ると、問題の箇所がかなり絞り込めます。

エラー処理全般について学びたい方には、エラーハンドリングとクラッシュ防止の基本もあわせてご覧ください。

フリーズを起こさないために

今回紹介した4パターンの共通点は、「処理の重さ・タイミング・状態管理に対して、適切なガードがない」という点です。Rork の AI は優秀ですが、プロンプトに「ローディング状態を必ず実装してください」「エラーハンドリングを入れてください」と明示することで、最初から問題の少ないコードが生成されます。

まずは今回の4パターンを頭に入れた状態でアプリを触ってみてください。「あ、これ②のパターンかも」とすぐに当たりがつくようになると、デバッグの時間が大幅に短縮できます。

React Native のパフォーマンスや状態管理についてさらに

シェア

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

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

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

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

関連記事

⬡ 開発ツール2026-07-24
同じ通信が同時に何本も飛ぶのを1本に束ねる — 参照カウント付きシングルフライト層の設計
起動直後に同じ API へ何本ものリクエストが同時に飛ぶ多重フェッチを、進行中の Promise を共有して1本に束ねる設計です。束ねる範囲を決めるキーの組み立て方、失敗した Promise を配り続けてしまう罠、呼び出し側の中断が全体を巻き込む罠、そして束ね率を数えて回帰を止めるテストまで、参照カウント付きシングルフライト層の実装を実測の通信ログとともに残します。
⬡ 開発ツール2026-05-18
Rork で Linking.canOpenURL が iOS だけ false を返す ─ LSApplicationQueriesSchemes 設定漏れの直し方
TikTok や X、LINE 公式アカウントへ飛ばす実装が iOS の本番ビルドだけで動かない症状を、LSApplicationQueriesSchemes の追加と EAS Build の再生成手順で確実に解消します。
⬡ 開発ツール2026-05-02
FlatList でカクつき始めたら読む — Rork アプリを FlashList v2 で快適にする実装手順
Rork で生成したアプリの長いリストが重くなったとき、FlashList v2 へ移行することでスクロールが大幅に滑らかになります。estimatedItemSize が不要になった v2 の思想を踏まえた、現実的な移行手順を解説します。