📝 はじめに
Reactでは、再レンダーのたびにコンポーネントが再実行されるため、
重い処理や配列の再計算があると、パフォーマンスに影響することがあります。
そんなときに活躍するのが useMemo フック です。
今回は、useMemoの基本的な使い方から、実際のサンプルコードまで解説します。
⚙️ 前提条件
この記事では以下の知識を前提としています。
-
Reactの基本文法(useState, useEffect)
-
JavaScriptの基本的な関数や配列操作の理解
🎯 今回の目標
-
useMemoの役割を理解する
-
再レンダー時の無駄な再計算を防ぐ方法を学ぶ
-
実際のコードで動作を確認する
💡 useMemoとは?
useMemo は、 「値をメモ化(記憶)して再利用する」 ためのReactフックです。
特に以下のようなケースで使用します👇
-
計算コストの高い処理を毎回実行したくない
-
同じ入力値で同じ結果を再計算するのを避けたい
🔹基本構文
const memoizedValue = useMemo(() => {
return heavyCalculation(value1);
}, [value2]);
第一引数(value1):計算関数。ここで実際に重い処理などを実行します。
第二引数(value2):依存配列。この値が変わったときだけ再計算されます。
※ 実際のコードでは、value1 と value2 が同じ変数(例:count)になることも多いです。
ここでは「計算に使う値」と「再計算をトリガーする値」を分かりやすく分けて記載しています。
🧩 サンプルコード:重い計算を最適化してみよう
✨ App.jsx
import React, { useState, useMemo } from "react";
const App = () => {
const [count, setCount] = useState(0);
const [text, setText] = useState("");
// 🔥 計算コストの高い関数(例:大きなループ)
const heavyCalculation = (num) => {
console.log("重い計算を実行中...");
let result = 0;
for (let i = 0; i < 1000000000; i++) {
result += i;
}
return result + num;
};
// useMemoを使わないと、textを変更しても毎回重い処理が走る
const memoizedResult = useMemo(() => heavyCalculation(count), [count]);
return (
<div style={{ padding: "20px" }}>
<h2>useMemoサンプル</h2>
<p>計算結果: {memoizedResult}</p>
<button onClick={() => setCount((prev) => prev + 1)}>カウント +1</button>
<div style={{ marginTop: "20px" }}>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="テキストを入力してみよう"
/>
<p>入力値: {text}</p>
</div>
</div>
);
};
export default App;
🧠 解説
-
useMemo を使うことで、count が変わらない限り heavyCalculation は再実行されません。
-
text の変更時には再計算されず、パフォーマンスが大幅に向上します。
🔍 useMemoとuseCallbackの違い
| フック | 目的 | 戻り値 |
|---|---|---|
| useMemo | 値をメモ化 | 計算結果 |
| useCallback | 関数をメモ化 | 関数 |
👉 「値を覚える」→ useMemo
👉 「関数を覚える」→ useCallback
⚠️ 注意点
-
むやみに使うのは逆効果:useMemo自体にもメモリコストがある
-
本当に重い処理や頻繁な再レンダー時のみ使用するのがおすすめ
-
コンポーネントを整理して最適化することが先決
🔄 ちなみにuseMemoを使わない場合のコード
以下のコードは、useMemo を使わずに重い処理をそのまま実行している例です👇
import React, { useState } from "react";
const App = () => {
const [count, setCount] = useState(0);
const [text, setText] = useState("");
// 🔥 重い処理(例:大きなループ)
const heavyCalculation = (num) => {
console.log("重い計算を実行中...");
let result = 0;
for (let i = 0; i < 1000000000; i++) {
result += i;
}
return result + num;
};
// ❌ useMemoなし:毎回再計算される
const result = heavyCalculation(count);
return (
<div style={{ padding: "20px" }}>
<h2>useMemoなしの例</h2>
<p>計算結果: {result}</p>
<button onClick={() => setCount((prev) => prev + 1)}>カウント +1</button>
<div style={{ marginTop: "20px" }}>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="テキストを入力してみよう"
/>
<p>入力値: {text}</p>
</div>
</div>
);
};
export default App;
🧠 解説
-
text を入力しても、コンポーネント全体が再レンダーされるため
→ heavyCalculation() が 毎回実行 される -
コンソールには、"重い計算を実行中..." が何度も表示される
-
入力フィールドの操作(軽い処理)にも関わらず、重い計算が走ってしまうのが問題
🧭 まとめ
-
useMemo は、再レンダー時の無駄な再計算を防ぐためのフック
-
重い処理や配列・オブジェクトの再生成に効果的
-
適材適所で使うことが重要
🏁 最後に
useMemo はReactの「パフォーマンス最適化」を理解するうえで欠かせないフックです。
次のステップとしては、useCallback と組み合わせて使うことで、より高度な最適化が可能になります。
実際の開発では、「本当に再計算が必要なときだけ実行する」 という考え方が大切です💡
最後までご覧いただきありがとうございます。次はuseCallbackの復習をしようと思いますので、そちらにも付き合ってもらえると嬉しいです。それではまた次の記事でお会いしましょう。