ReactでRerenderが分かるようにする
始めに
Reactではパフォーマンスが非常にシビアで、何も考えないと毎回rerenderされてしまい動きがかなり重くなる可能性があります。しかしどのコンポーネントがいつrerenderが走っているかパッと見ることができないため中々気づけません。rerenderの検出はReact Developer Toolsで以下の記事などを参考することで確認することができます。
上記の設定でほとんどは事足りるかもしれませんが、CodeSandbox上だと上手く確認できなかったり、render回数を表示したりなど自分で色々いじりたい場合は自作した方が良いので、その方法について備忘録としてまとめました。
renderの回数を表示する
renderの回数を表示するには、単純にコンポーネントのrenderメソッドを呼ばれた回数をカウントすると良いです。ただ useState
だと更新メソッドを呼ぶとまたrerenderしてしまうため、useRef
でライフサイクルに影響を与えないようにします。
import { FC, useRef } from "react";
export const RenderCount: FC = () => {
const renderCountRef = useRef(0);
renderCountRef.current += 1;
return <div>render count: {renderCountRef.current}</div>;
};
render時にアニメーション表示する
render回数が表示されるのは良いことですが、React.StrictMode
でrenderしている場合は余計にrenderされて本番でrenderされる回数が分かりづらくなってしまいます。単純にrerenderされたかを可視化するには以下の記事のようにフェードで表示するのが良さそうです。ただ具体的な実装がこの記事からでは見つけられなかったので自己流で実装しました。
CSSアニメーションで実装
まず最初に思い浮かぶのはCSSアニメーションです。以下のようなCSSアニメーションを設定したらフェード表示できそうです。
@keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
transform: translateY(-10px);
}
}
.Item {
animation: fadeOut 1s forwards;
color: red;
}
あとはrerenderするたびにこのアニメーションが発火すれば良いですが、アニメーションだけ発火させる方法が分からなかったので key
を更新してDOM自体を作り直す方法にしました。前のセクションで紹介したrender回数をカウントするやり方を使ってその数を key
に設定することで毎回違うDOMを生成してくれるようになるため、目的を達成することができます。
import { FC, useRef } from "react";
import styles from "./NotifyRerender.module.scss";
export const NotifyRerender: FC = () => {
const renderedCountRef = useRef(0);
renderedCountRef.current += 1;
return (
<div
// keyを変更して毎回DOMを作り直してアニメーションを再発動させる
key={renderedCountRef.current}
className={styles.Item}
>
Rerender
</div>
);
};
Web Animations APIで実装
CSSアニメーションの場合だとCSSファイルを用意したり、keyでDOMを再生成したりする必要があって割と手間だったので別な方法も考えました。JSでアニメーションをする場合は今だとWeb Animations APIというものが使えるため、そのやり方も試してみました。
useEffect
で第二引数を渡さない場合は毎回実行される仕様を活かし、DOMさえ取得できればeffectするたびにanimateメソッドを実行するだけで良さそうです。
import { FC, useRef, useEffect } from "react";
export const NotifyRerenderByWebAnim: FC = () => {
const elRootRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
if (elRootRef.current == null) {
return;
}
elRootRef.current.animate(
[
{ opacity: 1, transform: "translateY(0)" },
{ opacity: 0, transform: "translateY(-10px)" }
],
{
duration: 500,
fill: "forwards"
}
);
});
return (
<div ref={elRootRef} style={{ color: "red" }}>
Rerender
</div>
);
};
動作確認
CodeSandboxで検証コードを書きましたので以下に貼っておきます。このサンプルではrender回数が余分に増えると分かりづらかったのでReact.StrictMode
は消しています。また一つだけコンポーネントをメモ化してrerenderが抑制されているかも確認できるようにしています。
終わりに
以上がReactのrerenderを可視化する方法でした。Reactはパフォーマンスがシビアに出るので自前でも確認する術を知れて良かったです。自作コンポーネントを配置する場合は環境変数で開発中だけ表示するようにしたら本番に影響は出ないと思うのでパフォーマンスをシビアにチェックしたい場合に仕込んでおくと良いかもです。
基本的にはReact Developer Toolsを設定するだけで十分そうですが、もし自作コンポーネントを配置して確認できるようにしたい時がありましたら参考にしていただけると幸いです。
Discussion