$ cat post.metadata

React Native Reanimated バージョン不一致エラー完全解説

React Native

React経験者がReact Nativeで遭遇しやすいReanimatedのバージョン不一致エラーの原因と解決策。3層構造の理解からキャッシュクリアまで。

$ cat post.content | render --format=markdown

React Native Reanimated バージョン不一致エラー完全解説

はじめに

React経験者がReact Nativeで遭遇しやすいエラーの一つが、Reanimatedのバージョン不一致エラー。以下のメッセージが表示される。

[Reanimated] Mismatch between JavaScript code version
and Reanimated Babel plugin version (3.10.1 vs. 3.16.7).

「Babelプラグイン?React Nativeでなぜ?」という疑問を生む複雑な問題だが、原因と対処がわかれば怖くない。

React Native Reanimatedとは

Webの世界との違い

ReactではCSS Transitions、Framer Motion、React Spring、GSAPなどでアニメーションを実装できる。これらはブラウザレンダリングエンジン上で動作する。

React NativeはネイティブUI(iOS: UIKit、Android: Android View)を操作する必要があり、ここで React Native Reanimated が活躍する。

なぜReanimatedが必要なのか

React Nativeアーキテクチャの構造:

JavaScript Thread (Reactコード、ビジネスロジック)
           ↓ Bridge(JSON経由の非同期通信)
Native Thread (UIKit / Android View)

JavaScriptとネイティブ間の通信はBridgeを経由しており、この非同期処理は60fpsのスムーズなアニメーションには遅すぎる。

ReanimatedはアニメーションロジックをUIスレッドで直接実行し、JavaScript Bridgeをバイパスすることで60fps(または120fps)のアニメーションを実現する。「Worklet」と呼ばれるコンパイル済みコードをネイティブ側で直接実行する仕組み。

エラーの正体:バージョン不一致が起きる理由

Reanimatedの3層構造

Reanimatedは3つの異なるレイヤーで構成されている。

Layer 1: JavaScript Codenode_modules 内のJavaScriptコード。npmやyarnでインストール。

Layer 2: Babel Plugin — ビルド時にWorkletを変換。babel.config.js で設定。

Layer 3: Native Code — iOS: Objective-C++、Android: Java。Podfile/build.gradleでインストール。

JavaScriptコードが3.16.7でも、Babelプラグインが3.10.1(キャッシュされた古いバージョン)の場合、Workletのコンパイル形式が不一致になる。

Webとの決定的な違い

項目Web (React)React Native
インストールnpm install ですぐ使えるnpm install → Babel設定 → pod install → ネイティブビルド
バンドラーWebpack / ViteMetro Bundler
キャッシュブラウザキャッシュMetro + ネイティブビルド + DerivedData
ネイティブ連携不要CocoaPods (iOS) / Gradle (Android)

エラーが発生する典型的なシナリオ

シナリオ1: 依存パッケージの競合

他のライブラリが古いReanimatedを内部に含有している場合:

your-app/node_modules/
├── react-native-reanimated@3.16.7 (あなたがインストール)
└── some-navigation-library/node_modules/
    └── react-native-reanimated@3.10.1 (ライブラリが内包)

シナリオ2: Metro Bundlerのキャッシュ

パッケージを更新しても、Metroが古いキャッシュを使い続ける場合:

bash
npm install react-native-reanimated@latest npm start # ← 古いBabelプラグインの出力を使用

シナリオ3: ネイティブビルドの未更新

JavaScriptパッケージは更新したが、ネイティブコードは古いまま、または pod install を実行していない場合。

解決方法:ステップバイステップ

ステップ1: バージョンの確認

bash
# yarnの場合 yarn why react-native-reanimated # npmの場合 npm ls react-native-reanimated

複数バージョンが表示されたら、それが原因。

ステップ2: バージョンの統一

package.json に以下を追加して、プロジェクト全体で単一バージョンを強制する。

json
{ "dependencies": { "react-native-reanimated": "^3.16.7" }, "resolutions": { "react-native-reanimated": "3.16.7" } }

npm の場合は resolutions の代わりに overrides を使う。

ステップ3: キャッシュの完全クリア

React Nativeは複数のキャッシュが存在するため、すべてクリアする必要がある。

bash
# 1. node_modulesの削除と再インストール rm -rf node_modules rm -rf package-lock.json # または yarn.lock npm install # 2. Metro Bundlerのキャッシュクリア npm start -- --reset-cache # 3. iOSのキャッシュクリア cd ios rm -rf Pods Podfile.lock ~/Library/Developer/Xcode/DerivedData pod install cd .. # 4. Androidのキャッシュクリア cd android && ./gradlew clean && cd ..

ステップ4: babel.config.jsの確認

Reanimatedのプラグインは 必ず最後 に記述する。

javascript
module.exports = { presets: ['module:@react-native/babel-preset'], plugins: [ '@babel/plugin-transform-runtime', // Reanimatedは必ず最後 'react-native-reanimated/plugin', ], };

ステップ5: アプリの再ビルド

bash
# iOSの場合 npx react-native run-ios --reset-cache # Androidの場合 npx react-native run-android # Expoの場合 npx expo run:ios

まとめ:解決の3原則

統一: resolutions / overrides でバージョンを統一

クリア: すべてのキャッシュ(Metro、Pods、DerivedData、node_modules)をクリア

リビルド: ネイティブコードを必ず再ビルド

Webでは「npm install したら終わり」だが、React Nativeは複数のレイヤーで構成されている。ネイティブアプリ開発の特性を常に意識することが重要。

$ echo $TAGS
#React Native#Reanimated#トラブルシューティング