実装ではなく振る舞いをテストし、StrictMode の二重呼び出しを活用し、Profiler でレンダーを測定します。
このレッスンを Kodokon で開くTesting Library の哲学は一文に集約されます。ユーザーが知覚するものをテストし、実装の詳細は決してテストしない。具体的には、アクセシビリティツリー を通じて DOM をクエリします。まず getByRole(クエリの女王であり、ついでにあなたの ARIA ロールを検証してくれる)、次に getByLabelText、getByText、そして最後の手段としてのみ getByTestId です。インタラクションには fireEvent よりも user-event を優先しましょう。fireEvent.change が孤立したイベントを発火するのに対し、user.type は本物のキーボードとまったく同じように、完全なシーケンス(focus、keydown、keypress、input、keyup)を再現します。findBy* のバリアントはクエリと非同期の待機を組み合わせます。読み込みステップの後には不可欠です。
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
test('adds a task to the list', async () => {
const user = userEvent.setup();
render(<TodoApp />);
await user.type(
screen.getByRole('textbox'),
'Review the report'
);
await user.click(
screen.getByRole('button', { name: /add/i })
);
expect(
await screen.findByText('Review the report')
).toBeInTheDocument();
});StrictMode は開発用のツールであり、本番環境ではまったく効果がありません。開発中、コンポーネント関数、state 初期化子、setState に渡された関数を 2 回 呼び出し、不純なレンダーをあぶり出します。2 回の実行が異なる結果を生むなら、隠れた副作用があるということです。React 18 以降は、各エフェクトを マウント、アンマウント、再マウント のサイクルにも通します。クリーンアップが完全に対称でないエフェクト(解除されないサブスクリプション、中断されないリクエスト)は即座に正体を現します。これは、React が state を保持したまま画面をアンマウントして再マウントする機能への直接的な準備です。
useEffect(() => {
const controller = new AbortController();
fetch('/api/user', { signal: controller.signal })
.then((res) => res.json())
.then(setUser)
.catch(() => {});
return () => controller.abort();
}, []);測定のために、React は <Profiler> コンポーネントと、DevTools 内のそのグラフィカルな対応物を提供します。その onRender コールバックは、とりわけ phase(mount、update、または nested-update)、actualDuration(このコミットでサブツリーのレンダリングに実際に費やされた時間)、そして baseDuration(メモ化を一切行わずに サブツリー全体をレンダリングする時間の見積もり)を受け取ります。両者の差はあなたの memo と useMemo の有効性を測ります。actualDuration が baseDuration を大きく下回っていれば、メモ化があなたのために機能しているということです。
import { Profiler } from 'react';
function App() {
return (
<Profiler
id="Sidebar"
onRender={(id, phase, actualDuration) => {
console.log(id, phase, actualDuration);
}}
>
<Sidebar />
</Profiler>
);
}baseDuration は何を表しますか?