React hookとは..?
React hookはReact16.8から追加された機能で、クラスコンポーネントでしか使用できなかったstateなどのReactの機能を関数コンポーネントで使用できる機能です。
公式ページは以下です。
この記事ではReact hookのAPIの1つであるuseCallbackについて紹介していこうと思います。
他のReact hookに関するAPIについても解説していますので、そちらもご覧ください。
- 【React.js】React hookを理解する! ~ useState編 ~
- 【React.js】React hookを理解する! ~ useEffect編 ~
- 【React.js】React hookを理解する! ~ useContext編 ~
- 【React.js】React hookを理解する! ~ useReducer編 ~
- 【React.js】React hookを理解する! ~ useCallback編 ~
- 【React.js】React hookを理解する! ~ useMemo編 ~ ◀︎◀︎◀︎ 今回のテーマ😃
- 【React.js】React hookを理解する! ~ useRef編 ~
useMemoとは…?
useMemo()は関数の結果を保持する機能を提供します。
保持した内容が同じ場合は再計算をせず保存した値を再利用します。
useCallback()との違いは、useCallback()は関数そのものをメモ化しますが、useMemo()は関数の戻り値をメモ化します。
使い方
- useMemo()の引数に、関数と依存配列を渡します。
- 依存配列を空で渡す場合
- 初期描画のレンダリングのみ、処理が実行されます。
- 初期に保存された値が常に再利用されるようになります。
- 依存配列に値を入れる場合
- 依存配列に指定した値が更新された時に処理を実行します。
- パフォーマンス最適化のために使用するようにします。
- 副作用の関数はuseEffect()でやるようにします。
const memoizedValue = useMemo(() => {
computeExpensiveValue(a)
}, [a]);
実際にコードで書いてみました。
import React, { useMemo, useState } from 'react';
import '../style.css';
const Counter5 = () => {
const [counter1, setCounter1] = useState(0);
const [counter2, setCounter2] = useState(100);
const countUpCounter1 = () => {
setCounter1(counter1 + 1);
};
const countUpCounter2 = () => {
setCounter2(counter2 + 100);
};
const weightFunction = useMemo(() => {
// 重い処理を実行する。
let i = 0;
while (i < 10) {
i++;
};
return counter2 * counter2;
}, [counter2]);
return (
<>
<p>カウンター1: {counter1}</p>
<p>カウンター2: {counter2}</p>
<p>weightFunctionResult: {weightFunction}</p>
<button onClick={countUpCounter1}>+1</button>
<button onClick={countUpCounter2}>+100</button>
<div className='line'></div>
</>
);
};
export default Counter5
import React from 'react';
import { Counter } from './components/index';
function App() {
return (
<div>
<p>useMemoのサンプルです</p>
<Counter5 />
</div>
);
}
export default App;
以下のように動作します。

weightFunctionに重い処理の結果をメモ化しており、依存配列にcounter2を指定しています。
つまり、counter2が更新されるcountUpConter2を実行するButtonコンポーネントをクリックした時のみ、それに依存するコンポーネントのみ再レンダリングされます。
countUpConter1を更新するButtonコンポーネントをクリックしてもcounter2は更新されないため、weightFunctionは実行されず、処理は軽いです。
- useMemo()を使用しない場合も試してみました。
以下のように修正しました。
import React, { useMemo, useState } from 'react';
import '../style.css';
const Counter5 = () => {
const [counter1, setCounter1] = useState(0);
const [counter2, setCounter2] = useState(100);
const countUpCounter1 = () => {
setCounter1(counter1 + 1);
};
const countUpCounter2 = () => {
setCounter2(counter2 + 100);
};
const weightFunction = () => {
// 重い処理を実行する。
let i = 0;
while (i < 10) {
i++;
};
return counter2 * counter2;
};
return (
<>
<p>カウンター1: {counter1}</p>
<p>カウンター2: {counter2}</p>
<p>weightFunctionResult: {weightFunction()}</p>
<button onClick={countUpCounter1}>+1</button>
<button onClick={countUpCounter2}>+100</button>
<div className='line'></div>
</>
);
};
export default Counter5
以下のように動作します。

weightFunctionに重い処理の結果をメモ化していないので、stateであるcounter1、またはcounter2のどちらかが更新されるたびに各コンポーネントが再レンダリングされてしまっています。
したがって、両方のButtonコンポーネントによるクリックで再レンダリングが行われているので、描画に時間がかかっています。
まとめ
今回の記事ではuseMemo()を紹介しました。
次回はuseRef()を紹介しようと思います。
参考記事

コメント