今、あなたはおそらく次のどちらかでしょう。デザイナーからLottieのJSONを渡されて「今日中にアプリに入れられる?」と聞かれているか、すでに組み込んでみて、開発では動くのに実機や起動時間、リリースビルドが絡むとコストがかさむと感じ始めているかです。
ここでLottie React Nativeが面白くなってきます。基本的なデモは簡単ですが、プロダクション品質の実装はそうではありません。その差は通常、インストール方法、再生の制御方法、そしてアニメーションファイルを単なるアセットとして扱うか、パフォーマンスバジェットの一部として扱うかにあります。
目次
- React NativeアプリにLottieが不可欠な理由
- Lottie開発環境のセットアップ
- 最初のLottieアニメーションを表示する
- Lottieアニメーションのコントロールを習得する
- 本番アプリ向けのパフォーマンスチューニング
- Lottieのよくある問題のトラブルシューティング
React NativeアプリにLottieが不可欠な理由
React Nativeで洗練されたプロダクトアニメーションを手作業で再現しようとしたことがあれば、その苦労は痛いほど分かるはずです。細かなモーションのディテールを詰めようとすると、タイミングのロジックや補間処理、プラットフォーム特有の挙動が山積みになります。見た目は「惜しい」ところまで仕上がっても、デザイナーが意図した完成度とは程遠いことがほとんどです。
Lottieはそのワークフローを一変させました。2016年にAirbnbがLottieをオープンソース化したことで、エンジニアがフレームごとに作り直す必要がなくなり、デザイナーがアニメーションを直接リリースできるようになり、モバイルアニメーションのあり方が変わりました。一部のエンタープライズ環境では、この変化によってモバイルアプリの開発コストが 最大40%、出典: AirbnbのLottie概要.
デザインとエンジニアリングの対立を解消する
Lottie React Native の大きな利点は、「JSON による美しいアニメーション」だけではありません。それは関心の分離です。デザイナーは After Effects で作業し、Bodymovin でエクスポートします。開発者は、モーションをカスタムの code に変換するのではなく、ネイティブバックエンドの再生で出力をレンダリングします。
これは重要です。アニメーション作業は広がりやすい性質があるためです。単一の祝賀状態のアニメーションでも、デザインレビュー、プロダクトレビュー、Android の動作、iOS の動作、アクセシビリティ、起動時のパフォーマンスに影響し得ます。Lottie はその影響範囲を狭めます。
実践的なルール: Lottie は、アニメーションがプロダクト体験の一部である場合に使用してください。単なる不透明度や移動のトランジションが必要な場合ではありません。
ユーザー体験の観点もあります。モーションはフィードバックを与え、アクションを確認し、ローディング状態をより生き生きとさせます。チームがポリッシュ、リテンション、インターフェースへの信頼性を真剣に考えている場合、アニメーションはその議論の一部です。より広い アプリのユーザー体験に関する議論 は、たいてい同じ結論にたどり着きます:素早いフィードバックは静的な画面に勝る。
Lottieの最適な活用シーン
Lottie React Native は、以下のような場合に最も効果的です:
- ブランドのマイクロインタラクション (いいね、保存、チェックマーク、購入成功状態など)
- オンボーディング用イラスト カスタム感を出したいが、動画の配信は避けたい場合
- ローディングや空状態 静的なUIが不完全に感じられる場合
- 機能の教育 GIFやMP4を埋め込まずにモーションを使いたい場合
解決できないのは、すべてのアニメーション問題ではない。基本的な画面遷移なら、React Native 標準のアニメーションツールの方がシンプルであることが多い。非常に大規模でインタラクティブなモーションシステムでは、JSON 形式がメリットではなくトレードオフになる可能性がある。このトレードオフは本番環境でより重要になるが、多くのチュートリアルはそこで早々に終わってしまう。
Lottie開発環境のセットアップ
インストール手順は、まず1つの判断に依存する: Expo マネージドワークフローか、ベア React Native か。メンタルモデルを混同しないこと。セットアップの問題の多くは、Expo 内でベアワークフローのガイドに従ったり、Expo がすべてのネイティブ詳細を抽象化していると誤解したりすることで発生する。

インストール前にワークフローを選択
アプリがExpo上で動作しており、最速のセットアップを求めている場合は、カスタムネイティブ作業が必要と確信している場合を除き、Expoのパスを維持してください。Bareアプリを使用している場合、または直接制御が必要なネイティブモジュールに依存している場合は、通常のネイティブ依存関係としてインストールし、iOSとAndroidの両方のビルドを即座に検証してください。
セットアップをプロジェクトタイプに合わせて整えることで、デバッグがどれだけ容易になるかを多くのチームは過小評価しています。そのため、カスタムネイティブ統合を構築する多くのチームは、 Expo EASの代替手段としてCapgo アプリが変更しにくくなる前に、早期に比較検討しています。
Expoマネージドセットアップ
Expoマネージドアプリでは、最小限に保ちましょう。
-
パッケージをインストール
npx expo install lottie-react-native -
Metroを再起動
npx expo start -c -
デバイスまたはシミュレーターで確認 まずローカルのJSONファイルから始め、非常に小さなアニメーションをレンダリングしてください。大きなアセットと新しいインストールを同時にデバッグしないでください。
Expoでは、いくつかの実用的な注意点があります:
- ローカルファイル優先: リモートアニメーションのデバッグは、ライブラリが動作していることを確認するだけなのに、ネットワークノイズを増やします。
- リリース時の挙動を早期にテスト: 開発モードでは、タイミングやパフォーマンス関連の問題が隠れることがあります。
- アセットパスに注意: JSONファイルの配置ミスは、「何もレンダリングされない」原因として最もよくあります。
Expoは「動く」状態に到達する最速ルートです。ただし、「スケールする」状態への最速ルートとは限りません。
Bare React Nativeでのセットアップ
bareプロジェクトでは、ネイティブ依存関係をすぐにインストールして検証してください。
-
パッケージをインストール
npm install lottie-react-native -
iOS Podsをインストール
cd ios && pod install && cd .. -
アプリを再ビルド
npx react-native run-iosまたは
npx react-native run-android
多くのクイックスタートガイドが省略しているポイントです。インストール後は、何か壊れていると判断する前にネイティブのフルリビルドを行ってください。アプリに正しくコンパイルされていないネイティブ依存関係は、Hot reloadでは救えません。
時間を節約するBare workflowのチェック項目
次に進む前に、この短いチェックリストを確認してください:
| 確認 | なぜ重要か |
|---|---|
| インストール後に再ビルド | ネイティブモジュールには再コンパイルが必要 |
実行 pod install |
これがないと iOS は安定しません |
| まずシンプルなローカル JSON を使います | インストール問題とアセット問題を分離します |
| 両プラットフォームを早期にテスト | AndroidとiOSでは失敗理由が異なる場合がある |
パッケージが正常にインストールされても最初のアニメーションが表示されない場合、インストールの問題ではなく、アセットパス、コンポーネントサイズ、再生設定の問題であることが多い。
最初のLottieアニメーションを表示する
最初の動作するアニメーションは地味でよい。ローカルファイル。固定サイズ。自動再生オン。ループは任意。条件付き再生、リモートJSON、複雑なレイヤーのエクスポートから始めないこと。

ローカルアニメーションファイルを追加
アセットフォルダがない場合は作成する:
assets/
animations/
success.json
名前はシンプルに。スペース、特殊な句読点、深いネストは避ける。 require() パスが明確な状態を保つこと。
Lottieを起動後のブランドローディングスクリーンやハンドオフに使う場合、起動パスに大きなアニメーションを入れる前に慎重に検討すること。 React Nativeスプラッシュスクリーン動作を調整している場合特にそう。.
LottieView でレンダリングする
大きな画面ファイルに直接埋め込まず、専用のコンポーネントを作成します:
import React from 'react';
import { View, StyleSheet } from 'react-native';
import LottieView from 'lottie-react-native';
export function SuccessAnimation() {
return (
<View style={styles.container}>
<LottieView
source={require('../assets/animations/success.json')}
autoPlay
loop={false}
style={styles.animation}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
alignItems: 'center',
justifyContent: 'center',
},
animation: {
width: 220,
height: 220,
},
});
これには3つの利点があります:
- ライブラリが正しくレンダリングされることを確認できる
- アセットのパスが正しく解決されることを確認できる
- 後で再生やサイズを調整する場所を1つに分離できる
基本を押さえないと、すぐにいくつかの落とし穴に遭遇します:
- 幅や高さがない: アニメーションは存在しても表示されないことがあります。
- 悪い例
require()パス: Metro がファイルを見つけられません。 - 無効なエクスポート: 一部の JSON ファイルは技術的には有効ですが、モバイルで想定通りに動作しない機能が含まれている場合があります。
最初のレンダリングはローカルかつ決定的に保ちましょう。テストするのはアーキテクチャではなく、統合です。
より良いファーストスクリーンテスト
コンポーネントを、ニュートラルな背景を持つシンプルな画面に配置します:
import React from 'react';
import { SafeAreaView, StyleSheet } from 'react-native';
import { SuccessAnimation } from './src/SuccessAnimation';
export default function App() {
return (
<SafeAreaView style={styles.screen}>
<SuccessAnimation />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
screen: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
});
iOS と Android のシミュレーター両方でこれが動作すれば、最初の大きなハードルを越えたことになります。次のステップは、さらにアニメーションを追加することではありません。declarative な props を使うべき時と、refs で直接制御すべき時を学ぶことです。
Lottie アニメーション制御の習得
Lottie React Native の多くのバグは、アニメーションが状態に反応する必要がある際に現れます。自動再生は簡単です。「ユーザーがアイテムをいいねした時にこのセグメントを再生し、いいねを解除した時に逆再生し、コンポーネントが再レンダリングしてもカクつかない」ようにするのが厄介です。

再生がシンプルな場合は props を使用
非インタラクティブな再生には、props で十分です。
<LottieView
source={require('../assets/animations/loading.json')}
autoPlay
loop
speed={1}
/>
このスタイルは以下に適しています:
- ローディングインジケーター
- 受動的オンボーディング用イラスト
- 装飾的な空状態
宣言的で読みやすいです。コンポーネントのマウント時に再生が始まり、Reactが制御を維持します。アニメーションロジックが完全にpropsで記述できる場合は、そこに留めておきましょう。
より高度な宣言的なケースは progressで、アニメーションフレームを別の値に紐付けます。モーションが外部の進捗ソースを反映すべき場合に有効ですが、一回限りのトリガーイベントにはやや不便です。
refsに移る前に、簡単な視覚的な比較を示します:
状態がアニメーションを駆動する場合にrefsを使用
ユーザーがタップ、トグル、またはアクションを完了した際、refsは通常より安全なツールです。実世界のデータは ハイブリッドフレームワークを使う開発者の68%が、 useEffect hooksでの不適切なref処理によるアニメーションのトリガー失敗を報告しています。だからこそ、 animation.current.play() それを中心に構築された信頼できるパターンが重要です。この Capacitorに焦点を当てたトリガー失敗の議論でも指摘されているとおりです。.
この問題はハイブリッドアプリに限りません。素のReact Nativeでも、特に開発者がrefを再生成したり、マウント前に再生をトリガーしたり、アニメーション呼び出しを不安定なEffectに結び付けたりすると発生します。
import React, { useRef, useState } from 'react';
import { Pressable } from 'react-native';
import LottieView from 'lottie-react-native';
export function LikeButton() {
const animationRef = useRef<LottieView>(null);
const [liked, setLiked] = useState(false);
const onPress = () => {
if (!animationRef.current) return;
if (liked) {
animationRef.current.play(60, 0);
} else {
animationRef.current.play(0, 60);
}
setLiked(!liked);
};
return (
<Pressable onPress={onPress}>
<LottieView
ref={animationRef}
source={require('../assets/animations/like.json')}
loop={false}
autoPlay={false}
style={{ width: 96, height: 96 }}
/>
</Pressable>
);
}
信頼性の高い「いいね」と「いいね解除」のパターン
このパターンは、本番環境では play() 既存の useEffect stateが変わるたびに呼び出すよりも安定します。
なぜうまくいくのか:
- イベントがアニメーションのトリガーを管理します: press イベントは再生を開始する安定したタイミングです。
- ref はローカルに保持され、永続化されます:
useRef不要な再レンダリングを回避します。 - コンポーネントは自動再生の競合を回避します: マウント時の挙動とユーザー操作による挙動が競合するのは避けたいところです。
避けたいよくあるミス:
-
ref が存在する前にトリガーする
もしanimationRef.currentが null の場合、再生は行われません。ガードしてください。 -
使用する
autoPlay命令型のコントロールで
再生のデフォルトオーナーを1つ選びましょう。 -
すべてを〜で動かす
useEffect
エフェクトは便利ですが、UIアクションではタイミングの問題を取り除くどころか、むしろ増やしてしまうことがよくあります。
タップに反応するアニメーションの場合、まずはタップハンドラー内でトリガーしてください。〜を使うのは、
useEffectそのインタラクションの外側に source of truth がある場合に限るべきです。
本番アプリ向けのパフォーマンスチューニング
Lottie React Nativeは、一見軽量に見えますが、チームが巨大なJSONファイルをapp bundleに詰め込み始めると、なぜ起動速度が低下したのかと頭を抱えることになるライブラリの一つです。問題はアニメーションそのものではなく、配信戦略にあります。

チームが陥りやすい罠
最もありがちなミスは、すべてのアニメーションをJavaScriptに直接バンドルし、それらすべてを早すぎるタイミングでロードしてしまうことです。〜によると、 Lottie JSONの誤った配信に関するこのガイドでは、JS bundleにLottie JSONのようなアセットを詰め込みすぎると、アプリの起動時間が ミドルレンジのデバイスで40%以上増加する可能性があります、ネイティブアセットとして移動しオンデマンドで読み込むことが重要な最適化です。
これは多くのチームが実際に経験していることと一致します。問題は小さな成功アニメーション1つではありません。積み重なる量です:
- オンボーディングモーション
- ローダー状態
- ECリアクション
- ブランド仕様の空画面
- ロケールファイルや、それらに隣接するバンドル重量の大きいアセット
アプリにすでに起動時の予算問題がある場合、Lottieファイルはそれを急速に悪化させます。
まず何を最適化するか
エクスポート自体から始めましょう。粗雑なアニメーションエクスポートは、後でパース、メモリ、レンダリング安定性においてコストを支払う複雑さを伴います。デザイナーのエクスポートをそのまま受け入れないでください。
この本番環境チェックリストを使用してください:
- 配信前にJSONを圧縮します: 小さいファイルほど読み込みやすく、起動時の肥大化しにくいです。
- 非クリティカルなアニメーションをJSバンドルから外します: 起動時のcodeは、アプリが即座に必要とするものに集中させます。
- 必要に応じてアニメーションを読み込む: 画面やアクションが必要になったタイミングでレンダリングする。
- 旧型デバイスでの挙動を監査する: 最新のシミュレーターでは、コストの高い再生が隠蔽されることがある。
- 大きな Lottie ファイルを起動時の装飾に使用しない: 初回インタラクションに不可欠でないものは、アプリの起動と競合すべきではない。
本格的なモバイルパフォーマンス改善に取り組むチームには、 AppLighter のモバイルパフォーマンスガイド が有用な補足資料となる。アニメーションの判断を、アプリの起動、レンダリング、フレームワークのトレードオフというより広い文脈で捉えられるためだ。
厳しい現実: 初回インタラクションを遅らせる美しいアニメーションは、デザイン上の勝利ではなく、通常はプロダクトのバグである。
React Native 単体にとどまらず、より広い視点も持つべきだ。ハイブリッドスタックで開発するチームも同様のアセット読み込み問題に直面し、より広範な Capacitor アプリ向けのアニメーションパフォーマンスガイド Lottie の判断にもそのまま当てはまります。
ローカルファイル vs リモート配信
ローカルファイルは予測可能で、オフラインでも動作し、ネットワークのばらつきを排除でき、テストもしやすいです。ただし、バンドルに詰め込みすぎやすい点には注意が必要です。
リモート配信ならバイナリをスリムに保てますが、アニメーションに可用性、キャッシュ、フォールバックの懸念が加わります。このトレードオフは非クリティカルなモーションなら許容範囲ですが、購入確認や認証成功などの主要な UX 状態ではリスクが高くなります。
実用的な分け方が効果的です:
| アセットの種類 | 推奨デフォルト |
|---|---|
| コアインタラクションアニメーション | ローカル保存で最適化、肥大化を防ぐ |
| たまに使うプロモーション用アニメーション | リモート取得(フォールバック付き) |
| 起動パス上のアニメーション | どうしても必要な場合のみローカルに保持 |
| たまにしか使わない機能紹介イラスト | オンデマンド読み込み |
このセクションのルールを1つだけ適用するなら、これです: LottieのJSONは単なる装飾ではなく、パフォーマンスに影響するアセットとして扱う.
Lottieのよくある問題のトラブルシューティング
Lottieが動かなくなるとき、原因はたいていありふれたものです。パスの間違い。サイズ指定漏れ。refのタイミング不良。JSONの肥大化。最速でデバッグするには、変数を減らすのが一番です。
Androidでアニメーションがレンダリングされない
まず、JSONファイルが正しく解決されることを確認してください。次に、コンポーネントに明示的なサイズを指定します。
<LottieView
source={require('../assets/animations/success.json')}
autoPlay
style={{ width: 200, height: 200 }}
/>
それでも失敗する場合は、既知の正常な別のアニメーションに置き換えてみてください。これにより、問題がファイルにあるのかセットアップにあるのかが分かります。
古いデバイスで再生がカクつく
通常、これはコンポーネント API ではなく、アセットの問題を示しています。
以下の修正を試してください:
- アニメーションの複雑さを減らす: AIに質問する
- 読み込みを遅らせる: 初期画面の処理と競合させない。
- 圧縮版をテストする: 圧縮ファイルの方が動作が良ければ、ボトルネックが特定できます。
- 複数のLottieビューを同時に表示しない: 1画面に複数のアニメーションを入れると、やりすぎになることがあります。
ref が null、または play が何もしない
null の ref は通常、マウント前にトリガーが発火したか、コンポーネントが条件付きで削除されたことを意味します。
if (animationRef.current) {
animationRef.current.play();
}
ref を安定させるには useRefを使い、アニメーションコンポーネントを不必要に再生成しないでください。ローカルビルドで奇妙な挙動が繰り返される場合は、古いキャッシュをクリアすると役立つことがあります。簡単な Yarn キャッシュのクリーンアップ手順 だけで、開発中の誤解を招くアセットの挙動を解消できることもあります。
画面サイズが変わるとアニメーションの見た目が崩れる
アニメーションにレイアウトを決めさせないでください。コンテナ内に配置し、意図したサイズを指定しましょう。
- アイコンやリアクションには固定の bounds を使う
- 大きなイラストにはアスペクト比を考慮したラッパーを使う
- 書き出しの意図した構図を確認せずに、全幅に引き伸ばすのは避けましょう
「Lottieが壊れている」という報告の多くは、実はレイアウト、アセット、タイミングの問題です。ライブラリは大抵、あなたが指示した通りに動いているだけです。
最後のデバッグ手段として、高度なpropをすべて外し、中央揃えのビューでローカルのアニメーションを1つだけレンダリングして、そこから組み立て直しましょう。この方法は、複雑な本番画面を眺めるより速く問題を切り分けられます。
Capgo は、ストアレビューを待たずに JavaScript、アセット、設定の修正を Capacitor アプリに配信できるようチームを支援します。ハイブリッドアプリを運用していて、より安全にアップデートをプッシュし、段階的なロールアウトを管理し、フロントエンドの問題から素早く復旧したいなら、 Capgo 一見の価値あり。