☘️
useMemo()を整理してみた
これは何か?
React初学者が 「useMemo()」 について学習内容をまとめた記事です。
今回は、重い処理がある関数を実装したアプリを例に「useMemo()」を実装してみます。
useMemo()とは何か?
「React.memo」・「useCallback()」と同様に「useMemo」を使用することで、不要な再レンダリングを防ぐことができパフォーマンス向上が期待できる。逆に言えば、これらを使用しなくてもアプリーケーション自体は動作する。
- 関数の結果を保持するためのフック
- レンダリングごとに不要な再計算をスキップする
useMemo()の構文
useMemo(() => 値の計算する関数の呼び出し,[値の計算に必要な要素の配列])
開発環境
- OS:macOS Monterey バージョン12.3.1
- 言語:TypsScript
- ライブラリー:React
環境構築
今回はNodeをインストールしている前提で進めます。
環境構築するディレクトリに移動し、「Create-React-App」を使用してReactのアプリ環境を構築します。
$ npx create-react-app@5.0.1 react-typescript-app --template typescript
You are running `create-react-app` 5.0.0, which is behind the latest release (5.0.1).
We no longer support global installation of Create React App.
Please remove any global installs with one of the following commands:
- npm uninstall -g create-react-app
- yarn global remove create-react-app
The latest instructions for creating a new app can be found here:
https://create-react-app.dev/docs/getting-started/
ファイル構成
react-typescript-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── ts.config.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
├── App.module.scss
├── App.css
├── App.tsx
├── App.test.js
├── index.css
├── index.js
├── logo.svg
├── serviceWorker.js
└── setupTests.js|
実装
今回はSassでスタイリングするので、node-sassをインストールします。
$npm install node-sass
App.tsx
import React, { useState } from "react";
import classes from "./App.module.scss";
function App() {
const [countA, setCountA] = useState<number>(0);
const [countB, setCountB] = useState<number>(0);
const calculatedResult = heavyFunction(countA);
return (
<div className={classes.app}>
<h2>useMemo</h2>
<p>Aをクリックすると「+100」, Bをクリックすると「+1」される</p>
<p>また、Aは+100されると同時にAの値が2倍された値が表示される</p>
<div className={classes.itemsWrapper}>
<div className={classes.items}>
<p>Aの値:{countA}</p>
<p>Aが2倍された値:{calculatedResult}</p>
<button
onClick={() => {
setCountA(countA + 100);
}}
>
A(重い処理)
</button>
</div>
<div className={classes.items}>
<p>Bの値:{countB}</p>
<button
onClick={() => {
setCountB(countB + 1);
console.log("Bをクリック");
}}
>
B
</button>
</div>
</div>
</div>
);
}
//useMemo()を実装した場合としていない場合の違いを確かめるために、Aボタン押した時に重い処理を入れます。
function heavyFunction(count: number) {
let i = 0;
while (i < 1000000000) {
i++;
}
console.log("重い処理を実行");
return count * 2;
}
export default App;
スタイリング
App.module.scss
.app {
margin-top: 40px;
text-align: center;
.itemsWrapper {
display: flex;
justify-content: space-around;
width: 40%;
margin-left: auto;
margin-right: auto;
.items {
button {
color: white;
font-weight: bold;
cursor: pointer;
text-align: center;
width: 150px;
padding: 15px;
margin: 10px;
border-radius: 180px;
background: #668ad8;
box-shadow: 0px 10px gray;
&:active {
box-shadow: none;
position: relative;
top: 5px;
}
}
}
}
}
完成画面
では、Bボタンを押した時のログを確認しながら、useMemo()を実装した時としていない時の違いをみていきます。
useMemo()を実装しない場合
Bボタンをクリックしてみます。
heavyFunction関数が実行されるため、Bの値が表示されるまで時間がかかります。
useMemo()を実装した場合
heavyFunctionをuseMemoでラップしてみます。
App.tsx
+ import React, { useMemo, useState } from "react";
- import React, { useState } from "react";
+ const calculatedResult = useMemo(() => {
+ return heavyFunction(countA);
+ }, [countA]);
- const calculatedResult = heavyFunction(countA);
Bボタンをクリックしてみます。
useMemoによりheavyFuncion関数の結果がメモ化されているため、heavyFunction関数は実行されません。
毎回、重い処理が実行される関数をメモ化することでパフォーマンス向上ができます。
最後までお読みいただきあありがとうございました。
もし誤っていることがあれば、ご指摘いただけます幸いです。
参考記事・参考書籍
Discussion