一般社団法人 全国個人事業主支援協会

COLUMN コラム

  • React Nativeのパフォーマンス最適化:New Architectureの活用法

React Nativeのパフォーマンス課題

React Nativeはクロスプラットフォーム開発の主力フレームワークとして広く採用されていますが、パフォーマンス面での課題は長年の懸念事項でしました。特に、JavaScriptとネイティブ間の通信がブリッジを経由する旧アーキテクチャでは、大量のデータ転送やアニメーション処理でボトルネックが発生しやすい状況でしました。

しかし、React Native 0.68から段階的に導入されているNew Architecture(新アーキテクチャ)により、これらの課題に根本的な改善がもたらされています。筆者が担当するアプリでも新アーキテクチャへの移行を完了し、体感できるレベルのパフォーマンス改善を実現しましました。本記事では、その実践知見をお伝えします。

New Architectureの三つの柱

JSI(JavaScript Interface)

New Architectureの中核となるのがJSIです。従来のブリッジはJSONシリアライゼーションを介してJavaScriptとネイティブ間で通信していましたが、JSIはC++レイヤーを通じて直接的な関数呼び出しを実現します。

// 従来のブリッジ方式(概念的な流れ)
// JS → JSON.stringify → Bridge → JSON.parse → Native

// JSIを使った直接呼び出し
import { multiply } from 'react-native-quick-crypto';

// C++を通じてネイティブ関数を直接呼び出し
const result = multiply(3, 7); // ブリッジ不要、同期的に実行可能

この変更により、データのシリアライゼーション/デシリアライゼーションのオーバーヘッドが排除され、特に高頻度な呼び出しで劇的な改善が見られます。

Fabric(新レンダリングシステム)

FabricはReact Nativeの新しいレンダリングシステムです。従来はUI更新がブリッジ経由で非同期に行われていたため、スクロール中のUI更新やジェスチャーレスポンスに遅延が生じることがありましました。Fabricではレンダリングパイプラインが再設計され、同期的なレイアウト計算と優先度ベースのレンダリングが可能になります。

// Fabricでは同期的なレイアウト計算が可能
import { useLayoutEffect } from 'react';
import { measure } from 'react-native-reanimated';

function AdaptiveComponent() {
const ref = useAnimatedRef();

useLayoutEffect(() => {
// 同期的にレイアウト情報を取得できる
const measurement = measure(ref);
if (measurement) {
console.log('Width:', measurement.width);
console.log('Height:', measurement.height);
}
}, []);

return {/* content */};
}

Turbo Modules

Turbo Modulesは、従来のNative Modulesの後継です。遅延ロード(Lazy Loading)に対応しており、アプリ起動時に全モジュールを初期化する必要がなくなりましました。これにより、起動時間の短縮に直結します。

// TurboModule の定義例(TypeScript spec)
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

export interface Spec extends TurboModule {
getDeviceName(): string;
getBatteryLevel(): Promise<number>;
}

export default TurboModuleRegistry.getEnforcing<Spec>(
'DeviceInfo'
);

Turbo Modulesでは型定義がCodegenによりネイティブコードに自動変換されるため、型安全性が保証されます。従来のNative Modulesで発生しがちだった型不一致によるランタイムエラーを防止できます。

パフォーマンス最適化の実践テクニック

リスト表示の最適化

大量データのリスト表示は、React Nativeで最もパフォーマンス課題が発生しやすい領域です。FlashListの導入は最初に検討すべき施策です。

import { FlashList } from '@shopify/flash-list';

function OptimizedList({ data }) {
const renderItem = useCallback(({ item }) => (
<ListItem title={item.title} />
), []);

return (
<FlashList
data={data}
renderItem={renderItem}
estimatedItemSize={80}
keyExtractor={(item) => item.id}
/>
);
}

FlashListはShopifyが開発したFlatListの高性能な代替コンポーネントです。セルのリサイクル機構が優れており、筆者のテストでは1万件のデータ表示でFlatList比約5倍のフレームレート改善を確認しましました。

アニメーションの最適化

React Native Reanimatedを活用し、アニメーション処理をUIスレッドで実行することが重要です。JSスレッドでのアニメーションは、ガベージコレクションなどの影響でジャンクが発生しやすくなります。

import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
} from 'react-native-reanimated';

function AnimatedCard() {
const scale = useSharedValue(1);

const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
}));

const onPressIn = () => {
scale.value = withSpring(0.95);
};

const onPressOut = () => {
scale.value = withSpring(1);
};

return (
<Animated.View style={animatedStyle}>
<Pressable onPressIn={onPressIn} onPressOut={onPressOut}>
{/* カード内容 */}
</Pressable>
</Animated.View>
);
}

移行時の注意点

New Architectureへの移行では、以下の点に注意が必要です。

  • サードパーティライブラリの対応状況を事前に確認すること。対応していないライブラリがある場合は互換レイヤーが使われるが、パフォーマンスメリットが薄れます
  • 段階的な移行が推奨されます。まずTurbo Modulesから始め、次にFabricへ移行するのが現実的
  • Hermes JSエンジンの有効化は新アーキテクチャの前提条件。未導入の場合は先にHermesへ移行する
  • テストの充実が不可欠。特にネイティブモジュールとの連携部分は入念にテストすること

まとめ

React NativeのNew Architectureは、長年の課題でしたパフォーマンス問題に対する本質的な解決策です。JSI、Fabric、Turbo Modulesの三つの柱により、ネイティブアプリに迫るパフォーマンスを実現できます。移行にはコストが伴いますが、ユーザー体験の向上を考えれば十分に価値のある投資です。

この記事をシェアする

  • Twitterでシェア
  • Facebookでシェア
  • LINEでシェア