はじめに
「React.memoを付けたのに、なぜかコンポーネントが再レンダリングされ続けている」——Reactでパフォーマンスチューニングをしていると、こうした場面に必ず一度は出くわします。React DevToolsのProfilerで再レンダリングが起きていることは分かっても、「なぜ起きたのか」「本当に避けられたのか」までは教えてくれません。
そこで役立つのがWhy Did You Renderです。Reactを監視対象に組み込むだけで、「このコンポーネントは本来再レンダリング不要だったのに、propsの参照が変わったせいで再レンダリングされました」といった具体的な原因をコンソールに出力してくれます。今回はこのライブラリの使い方を、実際に動くサンプルとともに紹介します。
Why Did You Renderとは
Why Did You Render(WDYR)は、Reactを「モンキーパッチ」することで再レンダリングを監視し、避けられたはずの再レンダリングが発生したときにその理由をコンソールへ出力してくれる開発support用ライブラリです。welldone-software社が公開しており、React本体だけでなくReact Nativeにも対応しています。
主な特徴
- 原因の可視化 - propsやstateが「値としては同じなのに参照が変わった」ケースを検出し、変更前後の差分をコンソールに表示します
- 細かい追跡設定 - アプリ全体を一括で監視することも、特定のコンポーネントだけをピンポイントで監視することもできます
- フックの追跡にも対応 -
useStateやuseSelectorのようなカスタムフックが再レンダリングの原因になっていないかも追跡できます - 開発時のみ有効化できる -
NODE_ENVで分岐させることで、本番ビルドには含めずに済みます
インストール
npm、yarnどちらでも導入できます。開発時にのみ使うツールなので--save-dev(-D)を付けるのが基本です。
npm install @welldone-software/why-did-you-render --save-dev
yarn add @welldone-software/why-did-you-render --dev
導入後は、エントリーポイントより前に読み込まれるwdyr.ts(または.js)のようなファイルを用意し、アプリの一番最初でインポートします。
// wdyr.ts
import React from 'react';
if (process.env.NODE_ENV === 'development') {
const whyDidYouRender = require('@welldone-software/why-did-you-render');
whyDidYouRender(React, {
trackAllPureComponents: true,
});
}
// index.tsx
import './wdyr'; // 必ず一番最初にインポートする
import { createRoot } from 'react-dom/client';
import App from './App';
createRoot(document.getElementById('root')!).render(<App />);
基本的な使い方
まずは最小構成で動かしてみましょう。以下のサンプルでは、ボタンを押すたびに親コンポーネントが再レンダリングされ、その際に子コンポーネントGreetingへ中身は同じでも参照が異なるオブジェクトを渡しています。React.memoで囲んでいるにもかかわらず再レンダリングされてしまう様子を、コンソールで確認できます。
ボタンをクリックすると、コンソールにGreetingの再レンダリング理由が表示されます。userプロパティの中身(name: '太郎')は変わっていないのに、オブジェクトの参照だけが毎回変わっているため再レンダリングが発生している——これがWDYRの言う「避けられた再レンダリング」です。useMemoでuserをメモ化すれば解消できます。
実践的なユースケース
特定のコンポーネントだけを個別に追跡する
trackAllPureComponentsはアプリ全体のmemoコンポーネントを監視するため、大規模なアプリではログが大量に出てノイズになりがちです。調査対象を絞りたいときは、コンポーネントにwhyDidYouRender = trueを直接設定することで、そのコンポーネントだけをピンポイントで追跡できます。
Badgeだけがログに出て、同じくmemoで囲んだFooterは静かなままなのが確認できます。「怪しいコンポーネントにだけ目印を付けて調査する」という、実務でそのまま使える絞り込み方です。
ログの出力内容をカスタマイズする
デフォルトのログはやや情報量が多く、チームによっては「コンポーネント名と理由だけ簡潔に見たい」ということもあります。そんなときはnotifierオプションで、ログ出力そのものを自由に組み立て直せます。
標準のログの代わりに、シンプルな1行メッセージが出力されるようになりました。社内のロギング基盤に合わせてフォーマットを変えたり、特定条件のときだけ通知したりといった応用がしやすくなります。
まとめ
Why Did You Renderを使うと、「なんとなく重い」で終わっていた再レンダリングの調査を、コンソールに出る具体的な差分情報をもとに進められるようになります。今回紹介したように、
trackAllPureComponentsでアプリ全体を大まかに監視するwhyDidYouRender = trueで怪しいコンポーネントだけを個別に追跡するnotifierでログ出力を自分たちの運用に合わせてカスタマイズする
といった使い分けができるので、開発規模やチームの運用に応じて柔軟に導入できます。useMemoやuseCallbackを「なんとなく」付けるのではなく、実際に効果があるかを確認しながらチューニングしたいときにぜひ試してみてください。
