RORK LABEN
TOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しましたTOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しました
記事一覧/開発ツール
開発ツール/2026-04-12中級

Rorkアプリが重い・遅い・フリーズする原因と解決法:パフォーマンストラブルシューティングガイド

Rorkで作ったアプリが重い・画面切替が遅い・フリーズするときの原因を体系的に診断し、実践的な解決策を解説します。React Native特有のパフォーマンス問題にも対応。

Rork515パフォーマンス30トラブルシューティング77React Native209Expo149デバッグ22最適化2

Rorkで作ったアプリを実機テストしてみたら「なんかもっさりしている」「画面の切り替えが遅い」「一定の操作でフリーズする」という経験はありませんか?

AIがコードを生成してくれるRorkの便利さの一方、パフォーマンス問題は自動では解決されません。ここではRorkアプリが重くなる代表的な原因を診断フローとともに整理し、具体的な修正方法をコード例つきで解説します。

よくあるパフォーマンス問題の症状チェックリスト

まず自分のアプリがどのパターンに当てはまるか確認しましょう。

スクロールがカクつく・引っかかる感じがする場合はFlatList・ScrollViewの問題、画面遷移のアニメーションがもたつく場合はNavigationの問題、特定のボタンを押したときだけ固まる場合は重い処理がメインスレッドをブロックしている可能性があります。またアプリ起動時間が長い場合は初期レンダリングの問題、長時間使っているとだんだん重くなる場合はメモリリーク、画像・動画の表示が遅い・チラつく場合は画像最適化の問題です。

それぞれの症状に対応した解決策を以下で解説します。

問題1:スクロールがカクつく

Rorkで生成されたリスト表示にmap()ScrollViewが使われている場合、データ件数が増えるとパフォーマンスが著しく低下します。

原因

ScrollViewはすべての子コンポーネントを一度にレンダリングするため、100件以上のデータがあると必ずカクつきます。

解決策:FlatListへの置き換え

// 重い実装(件数が増えるとカクつく)
<ScrollView>
  {items.map((item) => (
    <ItemCard key={item.id} item={item} />
  ))}
</ScrollView>
 
// 軽い実装(画面外の要素は仮想化してレンダリングを省略)
<FlatList
  data={items}
  keyExtractor={(item) => item.id.toString()}
  renderItem={({ item }) => <ItemCard item={item} />}
  initialNumToRender={10}
  maxToRenderPerBatch={5}
  windowSize={5}
  removeClippedSubviews={true}
/>

FlatListに切り替えただけで、スクロールのカクつきが解消されるケースが多いです。

ItemCardコンポーネントの最適化

リストアイテムのコンポーネント自体が重い場合はReact.memoでラップします。

const ItemCard = React.memo(({ item }: { item: Item }) => {
  return (
    <View style={styles.card}>
      <Text style={styles.title}>{item.title}</Text>
      <Text style={styles.description}>{item.description}</Text>
    </View>
  );
});
ItemCard.displayName = 'ItemCard';

問題2:画面遷移が重い・アニメーションがもたつく

画面遷移時にアニメーションがカクつく場合、重い初期化処理が原因であることが多いです。

原因の診断

const HeavyScreen = () => {
  const startTime = useRef(Date.now());
 
  useEffect(() => {
    const renderTime = Date.now() - startTime.current;
    console.log(`[パフォーマンス] HeavyScreen レンダリング時間: ${renderTime}ms`);
    // 100ms超えたら要注意、500ms超えたら問題あり
    if (renderTime > 100) {
      console.warn('[警告] レンダリングに時間がかかっています:', renderTime, 'ms');
    }
  }, []);
 
  return <View>...</View>;
};

解決策:Lazy Loadingで遷移先の初期化を遅延

import { lazy, Suspense } from 'react';
 
const HeavyDetailScreen = lazy(() => import('./HeavyDetailScreen'));
 
function App() {
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <HeavyDetailScreen />
    </Suspense>
  );
}

解決策2:画面表示後に非同期でデータ取得

const ProductListScreen = () => {
  const [products, setProducts] = useState<Product[]>([]);
  const [isReady, setIsReady] = useState(false);
 
  useEffect(() => {
    const loadProducts = async () => {
      try {
        const data = await fetchProducts();
        setProducts(data);
      } catch (error) {
        console.error('商品データの取得に失敗:', error);
      } finally {
        setIsReady(true);
      }
    };
    loadProducts();
  }, []);
 
  if (\!isReady) return <SkeletonLoader />;
  return <FlatList data={products} renderItem={({ item }) => <ProductItem item={item} />} />;
};

問題3:特定の操作でフリーズする

ボタンタップ後に一瞬画面が固まる場合、重い処理がJavaScriptのメインスレッドをブロックしています。

原因の特定と修正

// メインスレッドをブロックする重い処理(問題あり)
const handleCalculate = () => {
  const result = bigData.map(item => expensiveCalculation(item));
  setResult(result);
};
 
// 非同期処理でメインスレッドを解放する(推奨)
const handleCalculate = async () => {
  setLoading(true);
  await new Promise(resolve => requestAnimationFrame(resolve));
  try {
    const result = await processInChunks(bigData, 100);
    setResult(result);
  } finally {
    setLoading(false);
  }
};
 
// 大量データを小分けに処理するユーティリティ
async function processInChunks<T>(
  data: T[],
  chunkSize: number
): Promise<T[]> {
  const results: T[] = [];
  for (let i = 0; i < data.length; i += chunkSize) {
    const chunk = data.slice(i, i + chunkSize);
    results.push(...chunk);
    // 各チャンク処理後にメインスレッドを解放
    await new Promise(resolve => setTimeout(resolve, 0));
  }
  return results;
}

問題4:アプリ起動が遅い

起動時間が3秒を超える場合、初期ロードの最適化が必要です。

不要なimportの削除

Rorkが生成するコードには使用していないライブラリのimportが含まれることがあります。

// 未使用のimportがバンドルサイズを増大させる(問題あり)
import { View, Text, TextInput, TouchableOpacity, Modal, Picker, DatePicker } from 'react-native';
 
// 使用するものだけをimport(推奨)
import { View, Text, TextInput, TouchableOpacity } from 'react-native';

スプラッシュスクリーンで起動時間を管理

import * as SplashScreen from 'expo-splash-screen';
 
SplashScreen.preventAutoHideAsync();
 
export default function App() {
  const [appReady, setAppReady] = useState(false);
 
  useEffect(() => {
    const prepare = async () => {
      try {
        await Font.loadAsync({ 'CustomFont': require('./assets/fonts/custom.ttf') });
        await Asset.loadAsync([require('./assets/images/logo.png')]);
        await initializeAppData();
      } catch (error) {
        console.warn('起動処理でエラー:', error);
      } finally {
        setAppReady(true);
      }
    };
    prepare();
  }, []);
 
  const onLayoutRootView = useCallback(async () => {
    if (appReady) await SplashScreen.hideAsync();
  }, [appReady]);
 
  if (\!appReady) return null;
  return (
    <View style={{ flex: 1 }} onLayout={onLayoutRootView}>
      <Navigation />
    </View>
  );
}

問題5:長時間使っているとだんだん重くなる(メモリリーク)

アプリを長時間使うほど遅くなる場合、メモリリークが疑われます。最もよくある原因はuseEffectのクリーンアップ忘れです。

診断と修正

// メモリリークが発生するパターン(クリーンアップなし)
useEffect(() => {
  const subscription = eventEmitter.addListener('update', handleUpdate);
  const timer = setInterval(fetchLatestData, 5000);
  // クリーンアップがない → コンポーネント削除後も処理が継続する
}, []);
 
// 正しいクリーンアップ(推奨)
useEffect(() => {
  const subscription = eventEmitter.addListener('update', handleUpdate);
  const timer = setInterval(fetchLatestData, 5000);
  return () => {
    subscription.remove();
    clearInterval(timer);
  };
}, []);
 
// 非同期処理でのメモリリーク対策
useEffect(() => {
  let isMounted = true;
  fetchData().then(data => {
    if (isMounted) setData(data); // マウント済みの場合のみstate更新
  });
  return () => { isMounted = false; };
}, []);

問題6:画像の表示が遅い・チラつく

expo-imageへの移行

import { Image } from 'expo-image';
 
<Image
  source={{ uri: 'https://example.com/product.jpg' }}
  style={styles.productImage}
  contentFit="cover"
  cachePolicy="memory-disk"
  placeholder={require('./assets/placeholder.png')}
  transition={200}
/>

ローカル画像のサイズ最適化にはpngquantが便利です。

# assets/imagesフォルダ内の全PNGを圧縮
find assets/images -name "*.png" -exec pngquant --force --quality=65-80 {} \;

Expo DevToolsでパフォーマンスを可視化する

問題の特定には、Expo DevToolsのPerformanceタブが非常に役立ちます。

npx expo start
# ターミナルで 'm' を押してMetro UIを開く
# Performanceタブでフレームレートとメモリ使用量を確認する

確認すべき指標は、FPS(フレームレート)は60fpsが理想で30fps以下はユーザーが体感できるカクつきになります。JS Threadは80ms以上かかる処理があれば要注意、UI Threadもブロックされていないか確認が必要です。


パフォーマンス計測の実践的な手法を

全体を振り返って

Rorkアプリのパフォーマンス問題は、以下の優先順位で対処すると効率的です。

スクロールのカクつきはFlatListへの置き換えとReact.memoで即効性があります。フリーズは重い処理を非同期化してメインスレッドを解放することで解決します。起動時間の問題は不要なimportを削除し、スプラッシュスクリーンで体験を改善します。メモリリークはuseEffectのクリーンアップを必ず実装することで防げます。画像の遅延はexpo-imageへの移行とキャッシュポリシーの設定で改善します。

パフォーマンス問題は「あとで直せばいい」と後回しにしがちですが、App Storeのレビューやユーザー離脱率に直結するため、リリース前に必ず実機でチェックする習慣をつけることをおすすめします。

Rorkの技術的なエラー対処全般についてはRorkアプリ ビルドエラー完全対処ガイドも合わせてご参照ください。また、パフォーマンスをさらに向上させる積極的な手法についてはRorkアプリ パフォーマンス最適化もご覧ください。

シェア

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

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

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

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

関連記事

開発ツール2026-04-20
Rork 生成コードで useEffect が無限ループする原因と直し方
Rorkで生成したReact NativeコードのuseEffectが無限ループする原因を5パターン解説。依存配列の設定ミス・オブジェクト依存・setState競合など具体的なBefore/Afterコードで根本修正する方法をまとめています。
開発ツール2026-07-10
React Compiler を Expo に入れて、手書き memo を 41 箇所消しました
Rork が生成した React Native 画面に React Compiler を導入し、再レンダリング回数を Profiler で実測しました。手書き memo/useCallback の削除判断、効かない箇所の見分け方、CI での回帰検知までをまとめています。
開発ツール2026-06-20
Rork が直せるバグと自分で直すバグを見分ける — エクスポートコードのトリアージ手順
Rork が自力で直すバグと、エクスポートしたReact Native/Expoコードを自分で手当てすべきバグを切り分けるトリアージ手順を、動くコードとともに整理しました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →