Writer: tokuyasu 更新日:2023/11/21
こんにちは、デジナーレ福岡オフィスの徳安です。
この記事では、React.memoについて説明します。
memoとは
1 |
const MemoizedComponent = memo(SomeComponent) |
構文
memo(Component, arePropsEqual?)
コンポーネントを memo でラップすることで、
そのコンポーネントのメモ化 (memoize) された
バージョンを得ることができる。
このメモ化されたバージョンのコンポーネントは、
親コンポーネントが再レンダーされても、
自身の props が変更されていない限り
通常は再レンダーされなくなる。
引数
Component: メモ化したいコンポーネント。
memo はこのコンポーネントを変更するのではなく、
メモ化が有効になった新たなコンポーネントを返す。
arePropsEqual(省略可能): レンダリング前後の Props の値を
受け取る関数を登録することができる。
ここで登録した関数が true/false を返すことで、
レンダリングの発生を制御させることが可能。
例えばreturn trueとしてしまうと、
子コンポーネントは永遠にレンダリングされることがなくなる。
再レンダーが発生する条件
再レンダーが発生する条件は、以下の3つ
1. stateが更新されたコンポーネント
2. propsが変更されたコンポーネント
3. 再レンダーされたコンポーネントの配下のコンポ-ネントすべて
(親コンポーネントが再レンダーされたら、子コンポーネントの再レンダーされる)
memoの使用法
memoを使用すると、propsの変更がない限り
親コンポーネントが再レンダーされても
Reactによって再レンダーされないコンポーネントを作成できる。
コンポーネントをメモ化するには、
対象のコンポーネントをmemoでラップし、
返された値を元のコンポーネントの代わりに使用する。
memo を使用することで、props が変更されない限り
再レンダーの必要がないということを
React に伝えることができる。
memoを使用しない場合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// 親コンポーネント import { useState } from "react"; export const App = () => { console.log("Appレンダリング"); const [num, setNum] = useState(0); const onClick = () => { setNum(num + 1); }; return ( <> <button onClick={onClick}>ボタン</button> <p>{num}</p> <Child /> </> ); }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// 子コンポーネント const style = { backgroundColor: "lightblue", padding: "8px", }; export const Child1 =() => { console.log("Child1レンダリング"); return ( <div style={style}> <p>Child</p> </div> ); }; |
下記のように、不要なレンダリングが発生してしまう。
memoを使用した場合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// 親コンポーネント import { useState, memo } from "react"; export const App = memo(() => { console.log("Appレンダリング"); const [num, setNum] = useState(0); const onClick = () => { setNum(num + 1); }; return ( <> <button onClick={onClick}>ボタン</button> <p>{num}</p> <Child /> </> ); }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 子コンポーネント import { memo } from "react"; const style = { backgroundColor: "lightblue", padding: "8px", }; export const Child1 = memo(() => { console.log("Child1レンダリング"); return ( <div style={style}> <p>Child</p> </div> ); }); |
メモ化することで、不要なレンダリングを抑えることができる。
memo を使用すべき場所
インタラクションが大まかなものである場合、通常メモ化は不要。
一方、描画エディタのような、
インタラクションが細かなもの(図形を移動させるなど)である場合は、
メモ化することで最適化することができる。
memoによる最適化は、
コンポーネントが全く同一のpropsで頻繁に再レンダーされ、
しかもその際レンダーロジックが高コストである場合に価値がある。
コンポーネントが再レンダーされても遅延を感じられない場合、memoは不要。
レンダー中に定義されたオブジェクトやプレーンな関数を渡しているなど、
コンポーネントに渡されるpropsが毎回異なる場合、
memo は全く無意味となる。
その場合は、useCallbackやuseMemoを一緒に使用する必要がある。
ここまで読み進めていただきありがとうございます。