frontend-react-best-practices は何をしますか?
Reactのパフォーマンス最適化ガイドライン。Reactコンポーネントの作成、レビュー、リファクタリング時に使用し、最適なレンダリングとバンドルパターンを確保します。Reactコンポーネント、フック、メモ化、バンドル最適化に関わるタスクで発動します。
はじめに
このガイドラインは、Reactアプリケーションのパフォーマンスを最大化するための実践的なアドバイスを提供します。各セクションでは、具体的な最適化手法とその適用タイミング、注意点について説明します。
メモ化
React.memo
- コンポーネントのpropsが変更されていない場合に再レンダリングをスキップします。
- 常に使用するのではなく、パフォーマンスの問題が確認されたコンポーネントにのみ適用してください。
- propsにオブジェクトや配列が含まれる場合は、比較関数をカスタマイズします。
const MyComponent = React.memo(function MyComponent(props) {
// コンポーネントのロジック
});
useMemo
- 高コストな計算結果をメモ化します。
- 依存配列が変更された場合のみ再計算されます。
- メモ化のオーバーヘッドが計算コストより低い場合に使用します。
const sortedList = useMemo(() => {
return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
useCallback
- コールバック関数をメモ化して子コンポーネントに渡す際に使用します。
- 過剰に使用せず、実際に最適化が必要な場合に限定します。
const handleClick = useCallback(() => {
setCount(prev => prev + 1);
}, []);
フックの依存関係
useEffect、useMemo、useCallbackの依存配列は常に完全に指定します。- 依存関係に過不足があると、バグや無限ループの原因となります。
- ESLintの
react-hooks/exhaustive-depsルールを有効にして自動チェックします。
useEffect(() => {
fetchData(userId);
}, [userId]); // userIdが依存関係に含まれていることを確認
バンドル最適化
コード分割
React.lazyとSuspenseを使用して、ルートレベルでコンポーネントを遅延ロードします。- 大きなライブラリやあまり使用されない機能を分割します。
const LazyComponent = React.lazy(() => import('./LazyComponent'));
遅延ロード
- 初期表示に不要なコンポーネントやリソースは、必要になるまでロードを遅延します。
- 画像や動画などのメディアアセットにも適用します。
レンダリング最適化
キー設定
- リストレンダリング時には各要素に一意で安定したキーを設定します。
- インデックスをキーに使用するとパフォーマンス低下やUIの不具合を引き起こす可能性があります。
{items.map(item => (
<ListItem key={item.id} data={item} />
))}
状態の局所化
- 状態を必要最小限のコンポーネントに限定します。
- 不必要な状態のリフトアップは避けます。
useEffectのクリーンアップ
- 副作用(購読、タイマー、イベントリスナーなど)はクリーンアップ関数で解放します。
- メモリリークや不要な更新を防止します。
useEffect(() => {
const subscription = dataSource.subscribe();
return () => {
subscription.unsubscribe();
};
}, []);
パフォーマンス計測
- React DevToolsのProfilerを使用してレンダリングパフォーマンスを計測します。
- 実際のパフォーマンス問題が確認された箇所だけを最適化します(早すぎる最適化は避ける)。
結論
これらのベストプラクティスを適切に適用することで、Reactアプリケーションのレンダリングパフォーマンスとバンドル効率を大幅に向上させることができます。パフォーマンス最適化は常に測定に基づいて行い、コードの複雑性を不必要に増やさないように注意してください。