こんにちは、ミナトです。
今回はReact HooksのuseMemoについて解説します。
useMemoとは?
useMemoはパフォーマンス最適化を行うためのフックです。
useMemoを利用すると関数の結果を保存(メモ化)しておき、引数に指定した値が変更された場合のみ再計算を行います。
毎回コンポーネントがレンダリングされる度に時間のかかる処理が実行される場合に利用することで、依存する値以外が変更された場合は、メモ化された値を返すので、パフォーマンスが最適化されます。
useMemoの使い方
const 変数名 = useMemo(関数, [依存する変数, 依存する変数]);
# 例
const memoValue = useMemo(() => func1(a, b), [a, b]);
useMemoの第一引数には、メモ化する対象の関数を指定します。
第二引数には、配列の形式で依存する値を指定します。useMemoで生成された値は第二引数に指定した値が変更された場合のみ再計算されます。(useMemoを利用しない場合、コンポーネントレンダリング時に毎回計算される)
第二引数に空の配列([])を指定した場合は初回レンダリング時のみ計算されます。
また、第二引数を指定しない場合は、毎回再計算されます。
useMemoの実装例
以下の実装例では、ボタンをクリックした際に値をカウントアップする簡単なアプリを作成します。
アプリ内では擬似的に時間のかかる関数を定義して、その戻り値を画面に表示します。
useMemoを利用する場合としない場合でどのように挙動が変化するか確認します。
React Appの作成
まずはReactのアプリを新規作成します。作成方法については以下の記事を参考にしてください。
コンポーネントの作成
componetを格納するディレクトリを作成します。(
)my-app/src/components/use_memo
の中にComponent1.jsを作成します。my-app/src/components/use_memo
UseMemoを利用しないパターン
まずはuseMemoを利用しないケースから確認します。
- useStateとuseMemoをインポート
- useStateでcount1とcount2を定義
- count1が偶数かどうかを判定する関数isEvenを定義(偶数ならtrue、奇数ならfalseを返す)
- コンポーネントでisEven()の結果に応じて偶数もしくは奇数を表示
- コンポーネントでcount1とcount2の値を表示するボタンを表示(ボタンクリック時にそれぞれの値が+1される)
import React, {useState, useMemo} from 'react';
const Component1 = () => {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const isEven = () => {
console.log('isEvenが実行されました。')
// 擬似的に時間のかかる処理を定義
let i = 0;
while (i < 1000000000) i++;
return count1 % 2 === 0;
};
return (
<div>
<h2>{isEven() ? '偶数': '奇数'}</h2>
<button onClick={() => setCount1(currentCount => currentCount + 1)}>count1: {count1}</button>
<button onClick={() => setCount2(currentCount => currentCount + 1)}>count2: {count2}</button>
</div>
);
};
export default Component1;
App.jsで上記で定義したComponent1.jsをインポートして表示します。
import './App.css';
import Component1 from './components/use_memo/Component1';
function App() {
return (
<div className="App">
<header className="App-header">
<Component1 />
</header>
</div>
);
}
export default App;
アプリを起動して、動作を確認してください。
count1とcount2のどちらをクリックしても再描画の際にisEven()が実行され、表示に時間がかかります。また、ブラウザの検証機能でコンソールを表示すると「isEvenが実行されました。」と表示されます。
useMemoを利用しない場合は、isEvenで利用していないcount2を更新した際もコンポーネントが再描画される際にisEvenが実行され、パフォーマンスが非常に悪い状態です。
UseMemoを利用するパターン
Component1.jsを以下のように修正してください。
偶数かどうかを判定する処理isEven関数の処理をuseMemoの第一引数渡します。
そして、useMemoの第二引数にはcount1を渡します。このようにすることでcount1が変更された場合のみisEvenが再計算されます。(count1が変更されていない場合はisEvenはメモ化された値を返します)
アプリを起動して、動作確認してみてください。
count1のボタンをクリックした場合はisEvenが再計算され、表示が変わるのに時間がかかりますが、count2のボタンをクリックした場合は即座に表示が切り替わります。
import React, {useState, useMemo} from 'react';
const Component1 = () => {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const isEven = useMemo(() => {
console.log('isEvenが実行されました。')
// 擬似的に時間のかかる処理を定義
let i = 0;
while (i < 1000000000) i++;
return count1 % 2 === 0;
}, [count1]);
return (
<div>
<h2>{isEven ? '偶数': '奇数'}</h2>
<button onClick={() => setCount1(currentCount => currentCount + 1)}>count1: {count1}</button>
<button onClick={() => setCount2(currentCount => currentCount + 1)}>count2: {count2}</button>
</div>
);
};
export default Component1;
まとめ
- useMemoを利用することで関数の計算結果を保存しておけるので、パフォーマンスを最適化できる
- useMemoの第二引数には依存する変数を配列形式で渡す
最後まで読んでいただき、ありがとうございます。
この記事が、「面白いな」、「勉強になったな」という方は、SNSでシェアしていただけると嬉しいです。