はじめに
Reactの特徴である親コンポーネントのstateやpropsが更新されると子コンポーネントも一緒に再レンダリングされます。
その子コンポーネントが重い処理を持っており、子コンポーネントにのみ変更があった際にレンダリングされるようにしたく色々試行錯誤してみました。
TL;DL
結論から言うとReact.memo
を使用すると実現できました。
export const ReactmemoChild: VFC<Props> = memo(({ open }) => {
console.log('再レンダリング!!!');
return <>{open && <p>child</p>}</>;
});
開発環境
ライブラリ | バージョン |
---|---|
React | 17.0.2 |
typescript | 4.5.4 |
詳細
結論の内容を説明する詳細な内容を説明
番号付き見出しのまとめ
1. React.memoとは
React.memo は高階コンポーネントです。
もしあるコンポーネントが同じ props を与えられたときに同じ結果をレンダーするなら、結果を記憶してパフォーマンスを向上させるためにそれを React.memo でラップすることができます。つまり、React はコンポーネントのレンダーをスキップし、最後のレンダー結果を再利用します。
React.memo は props の変更のみをチェックします。React.memo でラップしているあなたのコンポーネントがその実装内で useState、useReducer や useContext フックを使っている場合、state やコンテクストの変化に応じた再レンダーは発生します。
デフォルトでは props オブジェクト内の複雑なオブジェクトは浅い比較のみが行われます。比較を制御したい場合は 2 番目の引数でカスタム比較関数を指定できます。
これはパフォーマンス最適化のためだけの方法です。バグを引き起こす可能性があるため、レンダーを「抑止する」ために使用しないでください。
簡単にまとめるとReact.memoはpropsの変更のみをチェックしてパフォーマンスを最適化するための方法ということになります。
2. React.memo実装前
import { useState } from 'react';
import { ReactmemoChild } from './ReactmemoChild';
export const Reactmemo = () => {
const [open, setOpen] = useState(false);
const [notOpen, setNotOpen] = useState(false);
const onClickButton1 = () => setOpen(!open);
const onClickButton2 = () => setNotOpen(!notOpen);
return (
<div style={{ textAlign: 'center' }}>
<button onClick={onClickButton1}>Childを表示</button>
<button onClick={onClickButton2}>Childとは関係ない</button>
<ReactmemoChild open={open} />
</div>
);
};
import { VFC } from 'react';
type Props = {
open: boolean;
};
export const ReactmemoChild: VFC<Props> = ({ open }) => {
console.log('再レンダリング!!!');
return <>{open && <p>child</p>}</>;
};
3. React.memo実装後
import { memo, VFC } from 'react';
type Props = {
open?: boolean;
};
export const ReactmemoChild: VFC<Props> = memo(({ open }) => {
console.log('再レンダリング!!!');
return <>{open && <p>child</p>}</>;
});
※親コンポーネントは一緒のため省略
まとめ
今回は子コンポーネントのpropsに変更があった時のみ際レンダリングするようにReact.memoを使用しました。
次回はメモ化(Memoization)という概念を深掘ってReact.memoの仕組みを深めたいと思います。