React Native アプリの Expo SDK アップデート(50 → 52 → 54)を実施しました

アソビュー - Qiita Advent Calendar 2025 - Qiita の7日目(表面)です。

はじめに

こんにちは。イベント・エンタメ事業開発部の kaorun343 です。

アソビューでは、販売しているチケットの QR コードを施設側で読み取るためのアプリ「Fast-In」を Expo を使用して開発しています。施設のスタッフがタブレットやスマートフォンでゲストの QR コードをスキャンすることで、瞬時にチケットの有効性を確認して入場処理を行えます。

2025 年、私たちは「Fast-In」に対して Expo SDK 50 から 52、そして 54 への段階的なアップデートを実施しました。Expo SDK の更新は、セキュリティパッチの適用や React Native 本体の改善を取り込むために定期的に必要となります。

本記事では、これら 2 回のアップデートを通じて遭遇した課題と、その解決方法について解説します。

前回のアップデートはこちら

tech.asoview.co.jp

Expo SDK 52 へのアップデート

Node.js のアップデート

Expo SDK 52 への更新において、最初にぶつかった問題は Node.js のバージョンでした。作業開始時点では Node.js v18.12.1 を使用していましたが、このまま Expo SDK 52 へ更新すると、expo start コマンド実行後にエラーが発生してアプリが起動できませんでした。

TypeError: os.availableParallelism is not a function
    at module.exports (/path/to/fast-in/node_modules/metro/src/lib/getMaxWorkers.js:5:20)

原因は、Expo SDK 52 が内部で使用している Metro が、Node.js v19.4.0 および v18.14.0 で追加された os.availableParallelism API を必要としていたためです。

nodejs.org

作業時の最新の LTS である v22.14.0 を選択しました。

Yarn Classic から Yarn Berry への移行

Node.js のアップデート後、さらに深刻な依存関係の問題に直面しました。

Expo 52 に移行後、アプリを起動すると以下のエラーが発生しました。

ERROR  index.js: [BABEL] /path/to/fast-in/index.js:
_traverse.visitors.environmentVisitor is not a function
(While processing: "/path/to/fast-in/node_modules/babel-preset-expo/build/index.js$0")

この _traverse.visitors.environmentVisitor API は @babel/traverse v7.25.0 で導入されたものですが、babel-preset-expo が依存する @babel/traverse のバージョンは v7.21 でした。つまり、直接依存していないパッケージの依存先(間接的な依存関係)である @babel/traverse を更新する必要があります。

github.com

Yarn Classic では間接的な依存関係を更新するコマンドが存在しないため、この問題を解決できませんでした。そこで、Yarn Berry (v2+) へ移行しました。Yarn Berry は既に他のプロジェクトでも利用しており、社内での知見もありました。

Yarn Berry では以下のコマンドで間接的な依存関係を最新版(または任意のバージョン)へ更新できます。

yarn up @babel/traverse --recursive

この --recursive オプションにより、依存関係ツリー全体で指定したパッケージを更新できました。

Expo SDK 本体のアップデート

Node.js と Yarn の環境が整ったところで、いよいよ Expo SDK 本体のアップデートに取り掛かりました。

yarn expo install expo@latest
yarn expo install --fix

react-native-elements の .defaultProps エラー

Expo SDK 52 では React 18 が使われており、React 18.3 以降で Function Component の .defaultProps が非推奨となりました。しかし、使用していた UI ライブラリ react-native-elements.defaultProps を使用していたため、エラーが発生しました。Yarn Berry の yarn patch コマンドを使ってパッケージに修正を加えました。このコマンドは、node_modules 内のパッケージを一時ディレクトリに展開して編集可能にし、変更内容を diff 形式で保存する機能です。

# パッケージを一時的な作業ディレクトリに展開
yarn patch react-native-elements
# 出力例: /private/var/folders/.../react-native-elements-npm-2.3.2-...

# 展開されたディレクトリで .defaultProps を削除し、デフォルト引数に書き換え
# 編集後、以下のコマンドでパッチを確定
yarn patch-commit -s /path/to/temp/dir

例えば、CheckBox コンポーネントでは以下のような修正を行いました。

変更前のコードは以下の通りです。

// 変更前

const CheckBox = (props) => {
  const { theme, ...rest } = props;
  // ...
};

CheckBox.defaultProps = {
  checked: false,
  title: "",
};

上記のコードを、このように修正しました。

// 変更後

const CheckBox = ({
  checked = false,
  title = "",
  onPress,
  ...rest
}) => {
  // ...
};

// .defaultProps の定義を削除

パッチを確定すると、.yarn/patches/ ディレクトリに差分ファイルが生成されます。

.yarn/patches/react-native-elements-npm-2.3.2-48370a17dd.patch

このパッチファイルは通常の diff 形式で、以下のような内容になります。

diff --git a/src/checkbox/CheckBox.js b/src/checkbox/CheckBox.js
--- a/src/checkbox/CheckBox.js
+++ b/src/checkbox/CheckBox.js
@@ -6,10 +6,14 @@ import CheckBoxIcon from './CheckBoxIcon';

-const CheckBox = (props) => {
-  const { theme, ...rest } = props;
+const CheckBox = ({
+  theme,
+  checked = false,
+  title = '',
+  onPress,
+  ...rest
+}) => {
   // ...
 };

-CheckBox.defaultProps = {
-  checked: false,
-  title: '',
-};

また、 package.json においてもそのパッチファイルを参照するように変更が追加されます。

{
  "dependencies": {
    "react-native-elements": "patch:react-native-elements@npm%3A2.3.2#~/.yarn/patches/react-native-elements-npm-2.3.2-48370a17dd.patch"
  }
}

これらを一緒に Git にコミットすることで、チームメンバー全員が yarn install 時に同じパッチが適用されるようになりました。

EAS CLI とモノレポ対応

EAS CLI のアップデートにより、モノレポ構成特有の問題に遭遇しました。アソビューでは、複数のサービスやアプリケーションを 1 つの Git リポジトリで管理するモノレポ構成を採用しています。

tech.asoview.co.jp

EAS CLI v15.0.0 から、ビルド時に git を利用するようになりました。これが弊社のモノレポ構成と相性が悪く、.easignore を使って「Fast-In」以外のディレクトリを無視しようとしましたが、うまく機能しませんでした。

github.com

環境変数を設定して git の利用を無効化し、.easignore のみを参照するように回避策を実装しました。

React Navigation 5 → 7 メジャーアップデート

Expo SDK 52 への移行で最も大きな変更の一つが、React Navigation のメジャーバージョンアップでした。

アップデートの動機

@react-navigation/native@5 が依存している @react-native-community/masked-viewreact@^16 に依存しており、「Fast-In」本体が依存している react@^18 とバージョンが合わなくなっていました。この依存関係の不整合を解消するため、React Navigation 7 への更新を決定しました。

JSX 動的定義から静的定義への移行

React Navigation 7 では、型安全性を大幅に向上させるため、スタックの定義方法を変更しました。

// JSX を使った動的な定義
<Stack.Navigator>
  <Stack.Screen name="Home" component={HomeScreen} />
  <Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
// 静的なオブジェクト定義
import type { StaticParamList } from "@react-navigation/native";

const screens = {
  Home: HomeScreen,
  Profile: ProfileScreen,
} as const;

type RootStackParamList = StaticParamList<typeof screens>;

declare global {
  namespace ReactNavigation {
    interface RootParamList extends RootStackParamList {}
  }
}

この変更により、TypeScript の型チェックの恩恵を容易に受けられるようになり、ナビゲーションのパラメータの型推論が正確になりました。

reactnavigation.org

React Navigation 7 では、navigate メソッドの挙動が変更されました。スタックに積まれているルートに navigate で戻ることができなくなり、モーダルにモーダルが重なったような UI になっていました。

この問題に対しては、navigategoBack に切り替えることで、適切な画面遷移を実現しました。

reactnavigation.org

Expo SDK 54 へのアップデート

Expo SDK 52 のアップデートから数ヶ月後、Expo SDK 54 へのアップデートを実施しました。Expo SDK 52 での経験を活かし、よりスムーズに進めることができました。

ESLint 9 系への対応

Expo SDK 54 では、ESLint のバージョンも更新する必要がありました。社内で使用していた共有 ESLint 設定が ESLint 9 系に対応していなかったため、今回の作業では外すことにしました。代わりに、Expo のデフォルトルールセットに近い構成へ移行しました。

SafeAreaView の非推奨化対応

React Native の大きな変更として、SafeAreaView の非推奨化がありました。

React Native の SafeAreaView が非推奨となったため、公式ドキュメントのガイドに従って react-native-safe-area-context を導入しました。

reactnative.dev

// 変更前
import { Platform, SafeAreaView, StatusBar, StyleSheet } from "react-native";

// 変更後
import { Platform, StatusBar, StyleSheet } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";

Fast-In においては、単純なインポート元の変更のみで移行が完了しました。

おわりに

本記事では、Expo SDK の更新について説明しました。今回のアップデートは、依存関係の解消や非推奨 API への対応など、様々な作業の連続でもありました。しかし、Yarn Berry への移行や React Navigation 7 への刷新を通じて、開発者体験を向上させることができました。 次のExpo SDKのアップデートでは「New Architecture」への移行が必要となります。今回のアップデートで最新の React や Expo のエコシステムに追従できたことで、次世代のレンダリングエンジンやネイティブモジュールの恩恵を享受する準備が整いました。

アソビュー株式会社では新しいメンバーを随時募集していますので、ご興味ある方はぜひご連絡ください。

www.asoview.com