useMemo: その概要、計算のキャッシュ、React Native

著者: IT Sectr 公開日: 2026-07-05 読了時間: 10 分

React NativeのuseMemoフックは、コンポーネントのレンダリング間で計算結果をメモ化し、高コストな操作の繰り返し実行を防ぎます。関数をメモ化するuseCallbackとは異なり、useMemoは返された値を保持し、指定された依存関係が変更された場合にのみ再計算します。React Docs、2024によると、メモ化は大規模な配列や複雑なデータ変換を伴う計算に特に効果的です。React Nativeでは、不要な再レンダリングが発生するたびにJavaScriptとネイティブスレッド間のブリッジ接続に追加の負荷がかかるため、useMemoを適切に使用することで、アニメーションの滑らかさとインターフェースの応答速度に直接影響を与えます。

重要ポイント

  • useMemo — 値をメモ化するためのReactフック。レンダリング間で関数の結果をキャッシュします
  • フックは2つの引数を受け取ります: 計算関数と依存関係配列
  • 値は少なくとも1つの依存関係が変更された場合にのみ再計算されます
  • React Nativeでは、useMemoはリストとアニメーションのパフォーマンス最適化に重要です
  • useMemoの過剰使用は、依存関係の比較コストによりパフォーマンスを低下させる可能性があります

React NativeにおけるuseMemoとは

useMemo — はReact標準ライブラリのフックで、追加パッケージなしでReact Nativeで使用できます。渡された関数が返す値をメモ化し、配列で指定された依存関係が変更されるまで、後続のレンダリングでこの値を再利用します。

フックの名前はmemoization(メモ化)に由来します — 高コストな関数の結果をキャッシュに保存する最適化手法です。同じ引数での後続の呼び出しでは、再計算する代わりにキャッシュされた値が返されます。

React Nativeのコンテキストでは、アーキテクチャ上の特性からメモ化が特に重要です。コンポーネントが再レンダリングされるたびに、JavaScript — ネイティブブリッジを介してデータが送信され、時間がかかります。コンポーネントに高コストな計算(リストのフィルタリング、並べ替え、フォーマット)が含まれている場合、再レンダリングのたびにそれらが繰り返され、JSスレッドがブロックされ、フレームドロップが発生します。

React Native Performance Docs、2024によると、ボトルネックは多くの場合、ネイティブコンポーネントのレンダリングではなく、レンダリング間のJavaScriptロジックの実行です。useMemoはまさにこの問題を解決します。

値のメモ化の仕組み

useMemoは関数と依存関係配列を受け取り、メモ化された値を返します。Reactは前回の値と依存関係配列を保存します。各レンダリングで、ReactはObject.isを使用して現在の依存関係を前回のものと比較します。少なくとも1つの依存関係が変更された場合、関数が再実行され、結果が保存されます。

構文と引数の渡し方

useMemoのシグネチャはウェブとReact Nativeで完全に同じです。最初の引数は、メモ化する値を返すパラメータなしの関数です。2番目は依存関係配列で、これが変更されると値が再計算されます。

js
import React, { useMemo } from 'react';

const sortedList = useMemo(() => {
    return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);

この例では、sortedListはitems配列への参照が変更された場合にのみ再計算されます。配列の内容は変更されたが参照が同じままの場合(ミューテーション)、useMemoは変更を検出しません — これは重要な制限です。

Object.isによる依存関係の比較

Reactは依存関係の比較にObject.isアルゴリズムを使用します。これは厳密な等価性===と同様に機能しますが、NaNを正しく処理します(+0と-0は異なるとみなされます)。つまり、プリミティブ型(文字列、数値、ブール値)の場合は値で比較され、オブジェクトと配列の場合は参照で比較されます。

js
// Object.is({'a': 1}, {'a': 1}) -> false (different refs)
// Object.is(42, 42) -> true (primitive by value)
// Object.is(NaN, NaN) -> true (correct handling of NaN)

このメカニズムを理解することは重要です: レンダリングのたびに依存関係に新しいオブジェクトを渡すと、依存関係が毎回変更されたとみなされるため、メモ化は無駄になります。

useMemoを使用するタイミング

useMemoは3つのシナリオで有効です: 高コストな計算、子コンポーネントへの安定したpropsの受け渡し、オブジェクトの参照IDの保持。React Nativeでは、モバイルアプリケーションのアーキテクチャ上、これら3つのシナリオが定期的に発生します。

高コストな計算

コンポーネントが大規模なデータ配列(フィルタリング、並べ替え、グループ化)やリソース集約型の数学的操作を処理する場合、useMemoは再レンダリングのたびにこれらの計算が繰り返されるのを防ぎます。モバイルアプリケーションでは、APIからのデータをリストに表示する前にフォーマットするのが典型的な例です。

子コンポーネントのための安定したProps

子コンポーネントがReact.memoでラップされている場合、propsが変更されたときにのみ再レンダリングされます。親内部でuseMemoなしでpropオブジェクトが作成されると、親のレンダリングのたびに新しい参照が作成され、子コンポーネントが不必要に再レンダリングされ、React.memoの利点が無効になります。

スタイル計算のメモ化

React Nativeでは、スタイルはしばしばpropsに依存します — 例えば、要素の幅は画面サイズに基づいて計算されます。useMemoを使用すると、入力パラメータが変更された場合にのみ、このような動的スタイルを計算できます。

useMemoが無駄なケース

useMemoは万能な最適化ツールではありません。いくつかのシナリオではメリットがなく、依存関係の保存と比較のオーバーヘッドによりパフォーマンスが低下する可能性さえあります。メモリの1バイト1バイトが重要なReact Nativeでは、効果を測定せずにuseMemoを盲目的に適用するのはアンチパターンです。

フックがメリットをもたらさない主なケースは3つです。第一に、計算が単純な場合(単純な加算、文字列連結)、useMemoのコストが計算自体のコストを上回ります。第二に、依存関係がレンダリングのたびに変更される場合 — 関数はそれでも実行され、メモ化は単に余分な作業を追加するだけです。第三に、コンポーネントのレンダリング頻度が低い場合、キャッシュストレージのオーバーヘッドは正当化されません。

Kent C. Dodds、2023によると、useMemoを追加する前に、React DevTools ProfilerまたはReact Nativeに組み込まれたパフォーマンスモニターを使用して問題を測定する必要があります。コンポーネントの再レンダリングに1ミリ秒未満しかかからない場合、メモ化は不要です。

  • 単純な計算 — 加算、連結、単純な三項演算子
  • まれな再レンダリング — 一度だけレンダリングされる静的画面
  • 変化する依存関係 — 依存関係がレンダリングのたびに新しい場合、メモ化は無駄
  • プリミティブ値 — 数値と文字列はメモ化を必要としません。そもそも軽量です

useMemoとuseCallbackの比較

useMemoとuseCallback — よく混同されるReactの2つのメモ化フックです。違いは、それらが保持するものにあります: useMemoは関数の実行結果(任意の値)を返し、useCallbackは関数自体を返します。どちらも依存関係配列を受け取りますが、構文が異なります。

特性useMemouseCallback
返り値関数実行の結果関数への参照
最初の引数値を返す関数メモ化する関数
典型的な使用法計算のキャッシュ子コンポーネント用の安定したコールバック
等価性useMemo(() => fn, deps)useCallback(fn, deps) === useMemo(() => fn, deps)

実際には、useCallbackは関数をメモ化する必要がある場合の、useMemoに対するシンタックスシュガーです。React Nativeでは、両方のフックが同様に頻繁に使用されます: useMemo — データ用(フォーマットされたテキスト、計算されたスタイル)、useCallback — イベントハンドラー用(onPress、onChangeText)。

useMemoの実践例

React NativeアプリケーションでのuseMemoの2つの実際のシナリオを見てみましょう。1つ目は検索クエリによる連絡先リストのフィルタリング、2つ目は画面サイズに基づく動的スタイルの計算です。

例1: リストの検索とフィルタリング

この例では、useMemoは、検索クエリとソースデータの両方が変更されていない場合、大きな連絡先リストのレンダリングごとの繰り返しフィルタリングを防ぎます。

js
const ContactList = ({ contacts, searchQuery }) => {
    const filteredContacts = useMemo(() => {
        if (!searchQuery.trim()) return contacts;
        const query = searchQuery.toLowerCase();
        return contacts.filter((c) =>
            c.name.toLowerCase().includes(query) ||
            c.phone.includes(query)
        );
    }, [contacts, searchQuery]);

    return (
        <FlatList
            data={filteredContacts}
            renderItem={renderContact}
            keyExtractor={(item) => item.id}
        />
    );
};

useMemoがない場合、フィルタリングはすべてのレンダリングで実行され、アニメーションやコンポーネントの他の部分の状態変更によって引き起こされるものも含まれます。useMemoを使用すると、フィルタリングはcontactsまたはsearchQueryが変更された場合にのみ実行されます。

例2: 動的スタイルの計算

React Nativeでは、スタイルはしばしば画面サイズやコンポーネントのpropsに依存します。useMemoを使用すると、このようなスタイルオブジェクトを一度計算し、依存関係が変更されるまで再利用できます。

js
const Card = ({ title, isSelected }) => {
    const cardStyle = useMemo(() => ({
        backgroundColor: isSelected ? '#e3f2fd' : '#ffffff',
        borderWidth: isSelected ? 2 : 1,
        padding: 16,
    }), [isSelected]);

    return (
        <View style={cardStyle}>
            <Text>{title}</Text>
        </View>
    );
};

このアプローチにより、cardStyleオブジェクトは、isSelectedが変更されるまで安定した(同じ参照)状態を保ちます。CardがReact.memoでラップされている場合、このパターンは子要素の不要な再レンダリングを防ぎます。

よくある質問

useMemoは何を返しますか?

useMemoはメモ化された値を返します — 最初の引数として渡された関数の実行結果です。後続のレンダリングでは、依存関係が変更されていない場合、Reactはキャッシュされた値を返します。

useMemoとuseCallbackの違いは何ですか?

useMemoは関数実行の結果(任意の値: 数値、オブジェクト、JSX)を返し、useCallbackは関数自体を返します。useCallback(fn, deps)はuseMemo(() => fn, deps)と同等です。

useMemoが不要なのはどのような場合ですか?

useMemoは単純な計算(加算、連結)、まれな再レンダリング、レンダリングごとに変更される依存関係、およびプリミティブ型には無駄です。useMemoを追加する前に、常にパフォーマンスを測定してください。

useMemoはパフォーマンスを低下させる可能性がありますか?

はい、不必要に使用した場合。Reactは以前の値をメモリに保存し、レンダリングのたびに依存関係を比較します。単純な計算の場合、これらの操作のオーバーヘッドがメモ化のメリットを上回ります。

useMemoの動作をデバッグするには?

React DevTools Profilerを使用してコンポーネントのレンダリング時間を測定します。React Nativeでは、デベロッパーメニューからパフォーマンスモニターも利用できます。再レンダリングに1ミリ秒未満しかかからない場合、useMemoは不要です。

まとめ

  • useMemo — 値をメモ化するためのReactフック。レンダリング間で関数の結果をキャッシュします
  • フックは計算関数と依存関係配列を受け取り、それらが変更された場合にのみ値を再計算します
  • React Nativeでは、useMemoはリスト、アニメーション、複雑な計算の最適化に特に重要です
  • 主なシナリオ: 高コストな計算、React.memo用の安定したprops、動的スタイル
  • useMemoはuseCallbackと異なります: 前者は値を返し、後者は関数を返します
  • useMemoの過剰使用は、依存関係の保存と比較のオーバーヘッドによりパフォーマンスを低下させます
  • useMemoを追加する前に、React DevTools ProfilerまたはReact Nativeのパフォーマンスモニターを使用して常に問題を測定してください

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください