Reactでアプリを開発していると、
コンポーネントが何度も再レンダリングされることで、
処理が重くなったり、パフォーマンスが低下したりする場面が出てきます。
特に、計算に時間がかかる処理や、依存関係が変わらないのに再計算が行われると、
アプリの動作が遅く感じられることがあります。
こうしたパフォーマンスの問題を解消するために役立つのが、ReactのuseMemoフックです。
この記事では、useMemoとは何か、どうやって使うのか、
そしてどんなときに役立つのかをわかりやすく解説します。
初心者の方でも理解しやすいように、実例や例えを交えながら進めていきます!
おねしゃす
useMemoとは?どんなときに使う?
useMemoの基本的な役割
useMemoは、Reactの「メモ化(memorization)」を実現するためのフックです。
簡単に言うと、useMemoを使うと「再計算が不要な処理をメモしておく」ことができます。
特に、計算コストの高い関数が何度も呼ばれるのを防ぎ、Reactのレンダリング速度を保つために便利です。
現実の例で考えると?
イメージとしては、「一度決めたルールをメモしておき、毎回考えなくてもいいようにする」ようなものです。
たとえば、旅行の際に毎回ホテルの場所を調べるのではなく、
あらかじめ場所をメモしておき、必要なときだけそれを確認するような感覚です。
同じ情報を何度も探さず、必要なときにサッと取り出せるのがuseMemoです。
useMemoの使い方
useMemoは、特定の処理を再実行する必要がない場合、その結果を保持するために使います。
具体的な使い方を見ていきましょう。
基本構文
useMemoの基本的な構文は以下のとおりです。
const memoizedValue = useMemo(() => {
// 計算処理
return 重い処理の結果;
}, [依存配列]);
JSX- 第一引数には、メモ化したい関数を記述します。
- 第二引数には依存配列(dependencies)を指定します。この配列の中にある値が変更されたときだけ関数が再実行され、結果が更新されます。依存配列が変更されない限り、メモ化した値が返されます。
具体例:計算の結果をメモ化する
たとえば、配列の中から特定の条件を満たす数を計算する場合、
条件が変わらない限り再計算を避けたいときがあります。
以下の例では、大きな配列を処理する重い関数をuseMemoでメモ化して、
パフォーマンスを向上させています。
import React, { useState, useMemo } from 'react';
function HeavyCalculationComponent() {
const [count, setCount] = useState(0);
const [inputValue, setInputValue] = useState('');
// 大きな配列から偶数だけをフィルターする重い処理
const heavyCalculation = (arr) => {
console.log('重い計算を実行中...');
return arr.filter((num) => num % 2 === 0);
};
const numbers = Array.from({ length: 100000 }, (_, i) => i + 1);
// useMemoで重い計算をメモ化
const evenNumbers = useMemo(() => heavyCalculation(numbers), [numbers]);
return (
<div>
<h3>計算結果: {evenNumbers.length}個の偶数があります</h3>
<button onClick={() => setCount(count + 1)}>カウント: {count}</button>
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="入力してみてください"
/>
</div>
);
}
export default HeavyCalculationComponent;
JSXコードの解説
- heavyCalculation関数は、100,000個の数値を含む配列から偶数をフィルターする、重い計算処理です。
- useMemoを使って
evenNumbersに計算結果をメモ化しています。このとき、依存配列にnumbersのみを設定しているため、numbersが変わらない限り再計算されません。 - これにより、
countやinputValueが変更されても、evenNumbersは再計算されず、パフォーマンスが向上します。
useMemoを使わない場合、この重い計算はcountやinputValueが変更されるたびに再計算されてしまいますが、useMemoでメモ化することで、無駄な計算を省くことができました。
入力フィールドやボタンクリックが原因で処理が重くなることを防ぐ
ユーザーが入力した内容やボタンをクリックした回数など、
頻繁に変更される情報に影響されないデータは、メモ化するのが効果的です。
useMemoを使うことで、パフォーマンス低下を防ぎながら、スムーズなユーザー体験を維持できます。
useMemoを使うときの注意点
useMemoは便利な反面、使いどころに注意が必要です。
すべての処理をメモ化しようとすると逆にパフォーマンスが悪化したり、コードが複雑になったりします。
以下のポイントを参考にして、適切な場面でuseMemoを活用しましょう。
1. 重い処理にのみ使う
useMemoは重い計算処理や、何度も実行されるとパフォーマンスに影響が出る処理にのみ使うようにします。
単純な値や頻繁に変わる値には向いていません。
2. 依存配列を適切に設定する
useMemoの依存配列が変化すると再計算が行われるため、依存配列には慎重に設定しましょう。
無駄な再計算を防ぐためには、変化がない値や不必要な値を依存配列に含めないことが重要です。
3. 過剰なメモ化を避ける
useMemoを多用すると、逆に管理が難しくなることがあります。
不要なメモ化を行うとパフォーマンスが悪化する場合もあるため、必要な処理に絞って使用するようにしましょう。
useMemoを活用した具体例:商品の合計金額を計算する
次に、useMemoの活用例として、カート内の商品の合計金額を計算する簡単なアプリを作ってみます。
カート内の商品のリストをメモ化することで、不要な計算を防ぎ、
ユーザーがカートの内容を確認する際の処理をスムーズにします。
import React, { useState, useMemo } from 'react';
function ShoppingCart() {
const [items, setItems] = useState([
{ id: 1, name: '商品A', price: 3000, quantity: 2 },
{ id: 2, name: '商品B', price: 5000, quantity: 1 },
{ id: 3, name: '商品C', price: 1200, quantity: 5 },
]);
const total = useMemo(() => {
console.log('合計金額を計算中...');
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}, [items]);
return (
<div>
<h2>カート内の商品</h2>
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name} - {item.quantity}個 - ¥{item.price * item.quantity}
</li>
))}
</ul>
<h3>合計金額: ¥{total}</h3>
</div>
);
}
export default ShoppingCart;
JSXコードの解説
- 商品情報を保持する
itemsは、複数の商品情報を配列で管理しています。 useMemoで合計金額を計算し、totalという変数にメモ化します。itemsが変更された場合のみ再計算が行われ、再計算が不要なときはメモ化された合計金額がそのまま使われます。
これにより、カート内の商品が変更されない限り合計金額の計算は行われないため、処理の効率化が図れます。
まとめ
ReactのuseMemoは、処理のメモ化を通してパフォーマンスを向上させるために役立つ便利なフックです。
特に、計算コストが高い処理や、頻繁な再計算が不要な場合に有効です。
useMemoを適切に使うことで、Reactアプリの処理速度を改善し、スムーズなユーザー体験を提供できます。
本記事で解説した内容を参考に、実際のプロジェクトでぜひuseMemoを活用してみてください!
あざした!
