以前、コード分割によるReactの表示パフォーマンスの改善についてまとめました。
それに引き続き、今回はReact.memo
が表示にどのような影響を与えるのかを検証し、その内容をまとめました。
React.memo
とは
React.memo
は高階コンポーネント(あるコンポーネントを受け取って新規のコンポーネントを返すような関数)です。
あるコンポーネントに同じpropsを与えられて同じ結果をレンダーするとき、そのコンポーネントをReact.memo
でラッピングしてあげることで、結果を記憶させることができます。
Reactが記憶したレンダー結果を再利用することで、表示パフォーマンスを向上させることができます。
ただ、React.memo
はパフォーマンス最適化のためだけの方法なので、レンダーを「抑止する」ために使用することは推奨されていません。
バグを引き起こす可能性があるので、下手に使わないほうがいいということですね。
ちなみに、Classコンポーネントで同様の実装を行うには、React.PureComponent
やshouldComponentUpdate()
というライフサイクルメソッドを使用します。
検証
Toggle PersonでPerson
コンポーネントを表示させて、Increase CountでButton Countを1ずつ増やしていくようなケースを考えました。
Person
コンポーネントはApp
コンポーネント内部にあります。
App
の作成
Person
の親コンポーネントであるApp
を作成します。
showPerson
の状態(true/false)でPerson
の表示を切り替えます。
import React, useState from 'react';
import logo from './logo.svg';
import './App.css';
import Person from './person.component';
const App = () => {
const initialState = {
count: 0,
person: { name: 'Jack', age: 22 },
showPerson: false,
}
const [state, setState] = useState(initialState)
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
{state.showPerson ? <Person person={state.person} /> : null}
Button Count: {state.count}
<button
onClick={() =>
setState((prevState) => ({
...prevState,
count: prevState.count + 1,
}))
}
>
Increase Count
</button>
<button
onClick={() =>
setState((prevState) => ({
...prevState,
showPerson: !prevState.showPerson,
}))
}
>
Toggle Person
</button>
</header>
</div>
);
}
export default App;
Person
の作成
Person
コンポーネントをつくります。
React.memo
未使用
通常のデフォルトエクスポートを行います。
import React from 'react';
const Person = ({ person }) => {
console.log('rendering');
return (
<div>
<p>{person.name}</p>
<p>{person.age}</p>
</div>
);
};
export default Person;
React.memo
使用
Person
をエクスポートするときにReact.memo
でラッピングします。
import React from 'react';
const Person = ({ person }) => {
console.log('rendering');
return (
<div>
<p>{person.name}</p>
<p>{person.age}</p>
</div>
);
};
export default React.memo(Person);
結果比較
Toggle Personを一回押し、Increase Countを何回か押してみたときの結果を比較しました。
Person
のレンダリング回数
React.memo
を使用しない場合、Toggle Personのあとに一回レンダリングされ、Increase Countを押すごとにレンダリングされていきます。
このように、親コンポーネントのApp
のstateが変化したときに子コンポーネントも再レンダーされます。
一方、React.memo
を使用した場合には、一度レンダリングされたら何回ボタンを押そうと再レンダリングされません。
このように、React.memo
を使うと、Person
のpropsの変更のみをチェックするため、親コンポーネントのApp
のstateが変化してもPerson
のレンダリングには影響がありません。
Personの
レンダリング時間
React.memo
を使用しない場合のPerson
の初期レンダリング時間は0.8 msです。
一方、React.memo
を使用した場合のPerson
の初期レンダリング時間は0.9 msと、使用しない場合よりも長くなります。
メモ化に伴い、最初のレンダリングに関してはReact.memo
を使用した方が時間がかかってしまいます。
このように、React.memo
にはデメリットもあるので、表示速度をdev-toolで測りながら、必要なときだけ利用を検討していくのがベストらしいです。
参考資料