◉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-05-06中級

Rorkアプリのアニメーションがカクつく — フレームドロップの根本原因を特定して直した手順

Rorkで生成されたアニメーションがカクつく問題の根本原因と修正手順を解説します。JSスレッドとUIスレッドの分離、useNativeDriverの使い方、フレームドロップの診断方法まで実践的にまとめました。

Rork585React Native239アニメーション10パフォーマンス33useNativeDriverトラブルシューティング85

Rorkで作ったアプリのアニメーションが、実機で確認するとカクカクします。そんな経験はないでしょうか。

プレビューでは問題なく動いているのに、TestFlightで試したら明らかにスムーズでない——個人開発をしていると、このギャップに気づくのは公開直前や公開後になりがちです。私自身、この問題に初めて直面したとき「Rorkが生成したコードだから仕方ない」と思い込んでそのままにしていた時期がありました。

ところが原因を調べてみると、多くの場合はたった1行の修正で解決できることがわかりました。フレームドロップが起きる根本的な仕組みと、診断から修正までの具体的な手順を実例とともに整理しました。

なぜアニメーションがカクつくのか — JSスレッドとUIスレッドの関係

React Nativeは、JavaScriptを処理するJSスレッドと、画面描画を担当するUIスレッドの2本柱で動いています。Rorkが生成するコードの多くはAnimated APIを使いますが、デフォルト設定ではアニメーションの計算がJSスレッド上で行われます。

問題は、JSスレッドがAPI通信やStateの更新など他の処理に追われると、アニメーションの計算が後回しになることです。60fpsを維持するには毎秒60回の計算が必要ですが、JSスレッドが詰まると1フレームが16.67msを超え、目に見えるカクつきとして現れます。

// ❌ Rorkが生成しがちなコード例 — JSスレッドで計算するためカクつく原因になる
const fadeAnim = useRef(new Animated.Value(0)).current;
 
Animated.timing(fadeAnim, {
  toValue: 1,
  duration: 300,
  // useNativeDriver が指定されていない(暗黙的にfalseになる)
}).start();

UIスレッドはJSスレッドとは独立して動くため、アニメーション計算をUIスレッドに委譲できれば、JSスレッドが混雑してもアニメーションはスムーズに動き続けます。

フレームドロップを診断する方法

修正の前に、まず本当にフレームドロップが起きているかを確認しましょう。React Nativeには開発ビルドで使えるパフォーマンスモニターが標準搭載されています。

実機でExpo開発ビルドを起動した状態で、メニューを開いて「Show Performance Monitor」を選択します。するとUI FPSとJS FPSの2つの数値がリアルタイムで表示されます。

見るべき数字:

  • UI FPSが60に近く、JS FPSだけが低下している場合はJSスレッドでアニメーション計算をしているサインです
  • 両方が低下している場合は、重いレンダリング処理が別の場所に潜んでいる可能性があります

Rork Companionを使っている場合は、コンソールログにAnimated: useNativeDriver was not specifiedという警告が出ていないかも確認してください。この警告が出ていれば、次の修正が直接効きます。

最もよくある原因と修正コード

① useNativeDriver: true を追加する

Rorkが生成するコードで最も多いのは、useNativeDriverが未指定またはfalseになっているケースです。

// ✅ 修正後 — UIスレッドで計算し、JSスレッドの混雑に影響されない
const fadeAnim = useRef(new Animated.Value(0)).current;
 
Animated.timing(fadeAnim, {
  toValue: 1,
  duration: 300,
  useNativeDriver: true, // ← この1行を追加するだけ
}).start();
 
// 複数アニメーションの組み合わせも同様に指定する
Animated.parallel([
  Animated.timing(fadeAnim, { toValue: 1, duration: 300, useNativeDriver: true }),
  Animated.spring(slideAnim, { toValue: 0, useNativeDriver: true }),
]).start();

重要な制限: useNativeDriver: trueは、opacity・transform(translateX, translateY, scale, rotate)など、レイアウトを変えないプロパティにのみ使用できます。width・height・backgroundColorなどレイアウト変更を伴うプロパティには使用できません。

// ❌ useNativeDriver: true を使えないプロパティ例(エラーになる)
Animated.timing(widthAnim, {
  toValue: 200,
  duration: 300,
  useNativeDriver: true, // width はネイティブドライバー非対応
}).start();
 
// ✅ 代替: transform.scaleX で横幅を変えているように見せる
Animated.timing(scaleAnim, {
  toValue: 2,
  duration: 300,
  useNativeDriver: true,
}).start();

② Reanimatedへの移行(複雑なアニメーションの場合)

スクロール連動アニメーションや、ジェスチャーと組み合わせた複雑な動きが必要な場合は、react-native-reanimatedを使う方が根本的な解決になります。Expoのマネージドワークフローではすでにインストール済みです。

// react-native-reanimated を使ったスクロール連動フェードイン
import Animated, {
  useAnimatedStyle,
  useSharedValue,
  withTiming,
} from 'react-native-reanimated';
 
function AnimatedCard() {
  const opacity = useSharedValue(0);
 
  useEffect(() => {
    opacity.value = withTiming(1, { duration: 400 });
  }, []);
 
  const animatedStyle = useAnimatedStyle(() => ({
    opacity: opacity.value,
  }));
 
  return (
    <Animated.View style={[styles.card, animatedStyle]}>
      {/* コンテンツ */}
    </Animated.View>
  );
}

ReanimatedのワークレットはデフォルトでUIスレッド上で直接実行されるため、JSスレッドを完全にバイパスします。スクロール連動やドラッグアニメーションでは、この差が体感として明確に現れます。

③ FlatListスクロール時にカクつく場合

アニメーション自体に問題がなく、スクロール時にカクつく場合は、FlatListのアイテムレンダリングが原因であることがほとんどです。

// ❌ スクロールのたびに重い計算が走るパターン
<FlatList
  data={items}
  renderItem={({ item }) => (
    <View style={[styles.item, { backgroundColor: item.color }]}>
      <Image source={{ uri: item.imageUrl }} />
      <Text>{item.title}</Text>
    </View>
  )}
/>
 
// ✅ React.memoでアイテムコンポーネントをメモ化する
const ItemComponent = React.memo(({ item }) => (
  <View style={[styles.item, { backgroundColor: item.color }]}>
    <Image source={{ uri: item.imageUrl }} />
    <Text>{item.title}</Text>
  </View>
));
 
<FlatList
  data={items}
  renderItem={({ item }) => <ItemComponent item={item} />}
  windowSize={5}         // 画面外の描画範囲を絞る
  initialNumToRender={8} // 初期表示件数を必要最小限に
  maxToRenderPerBatch={5} // 一度に追加するアイテム数を制限
/>

④ 画面遷移直後のカクつき — 重い処理を遷移完了後に遅延させる

画面遷移のアニメーション中にデータ取得や重い初期化を走らせると、遷移そのものがカクつきます。InteractionManagerを使うと、アニメーション完了後まで重い処理を遅延できます。

import { InteractionManager } from 'react-native';
 
useEffect(() => {
  const task = InteractionManager.runAfterInteractions(() => {
    // 遷移アニメーション完了後に実行される
    loadHeavyData();
  });
  return () => task.cancel();
}, []);

私のアプリでは、一覧→詳細の遷移でこのパターンに変えただけで「遷移の引っかかり」の体感が明確に変わりました。遷移直後にuseEffectで重い処理を即実行しているコードは、Rorkの生成コードに限らずよく見かける形なので、遷移系のカクつきではまずここを疑ってみてください。

Rorkへのプロンプトで最初から問題を防ぐ

修正よりも、最初から問題を発生させないプロンプトを使う方が効率的です。Rorkにアニメーションを追加させる際は、以下のように明示的に指示するとuseNativeDriverが最初から設定された状態でコードが生成されやすくなります。

「フェードインアニメーションを追加してください。
useNativeDriver: true を必ず使用し、60fps を維持できる実装にしてください。」

「スクロール連動のアニメーションは react-native-reanimated を使用してください。」

実際に試したところ、明示的に指定することで生成コードの品質が安定しました。指定なしだと、シンプルなケースではuseNativeDriverを付けてくれることもありますが、複雑なアニメーションでは省略されることがあります。

修正後の確認チェックリスト

修正後は以下を実機(TestFlightビルド)で確認してください。シミュレーターはパフォーマンスが実機と大きく異なるため、最終確認は必ず実機で行いましょう。

  • パフォーマンスモニターで UI FPS と JS FPS が両方60近くを維持しているか
  • スクロール中もアニメーションがスムーズに動くか
  • コンソールに useNativeDriver was not specified 警告が出ていないか
  • 古い端末(iPhone XS相当)でも許容できるスムーズさか

アニメーションのスムーズさは、ユーザーがアプリの「質」を感じる重要な要素です。useNativeDriver: trueの追加という、たった1行の修正で体験が大きく変わるケースが多いので、カクつきが気になったらまずここを確認してみてください。同じ症状で悩んでいる方の助けになれば幸いです。

シェア

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

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 の思想を踏まえた、現実的な移行手順を解説します。