Reactプロジェクトでは、反射的にuseEffect
を使用することがよくありますが、このアプローチは時としてコードを不必要に複雑にする可能性があります。この記事では、useEffect
が不要なケースと、その誤用を避けてコードを最適化する方法について見ていきます。
useEffect
の役割を理解する
useEffect
フックは、サブスクリプションやメインのレンダリングフロー外で行う必要のある操作などの副作用を管理するのに有用です。しかし、一般的なユースケースの中には、useEffect
なしで簡素化できるものがあります。
1. useEffect
を使用しない状態の初期化
コンポーネントのマウント時にpropsや初期値に基づいて状態を初期化したい場合がよくあります。この状態を設定するためにuseEffect
を使用する代わりに、useState
で直接行うことができ、コードがより明確になり、不必要な呼び出しを防ぐことができます。
useEffect
を使用する悪い例:
useEffect
を使用しない良い例:
ここでは、useState
で関数を使用してgreeting
状態を直接初期化できます:
このアプローチにより、コードがより簡潔になり、アプリケーションを遅くする可能性のある余分な効果を追加することを避けられます。
2. 派生値の計算
状態やpropsに基づいて値を計算する必要がある場合は、useEffect
ではなく、派生変数やmemo
を使用することを検討してください。
useEffect
を使用する例(避けるべき):
useEffect
を使用しない解決策:
ここでは、total
値をレンダリング中に直接計算でき、useEffect
に依存する必要はありません:
この方法は、よりクリーンなだけでなく、追加の状態管理が不要になります。
3. 重い計算のためのuseMemo
の使用
高コストな計算や複数の変数に依存する計算には、状態を管理するためのuseEffect
を必要とせず、各レンダリングでロジックを再実行することを避けるためにuseMemo
を使用します。
useEffect
を使用する例:
useMemo
を使用した最適化アプローチ:
ここでは、useMemo
を使用することで、効果を管理する必要なく結果をメモ化でき、コンポーネントをより予測可能で効率的にします。
4. 制御されたコンポーネントのプロパティの同期
制御された入力の管理には、親コンポーネントの状態と入力値を同期させるためにuseEffect
を使用する必要はありません。単にpropsとコールバック関数を使用して、この状態を効率的に管理できます。
useEffect
を使用する例(不要):
useEffect
を使用しない解決策:
propsを直接使用することで、コードが簡素化され、不必要な状態更新を減らすことでパフォーマンスが向上します。
5. レンダリング中のDOM直接操作
状態に基づいてスタイルやクラスを適用したい場合、useEffect
を使用する必要はほとんどありません。Reactはレンダリング中にこの種の同期をうまく処理します。
useEffect
を使用する例:
useEffect
を使用しない解決策:
結論
useEffect
を避けることで、多くの場合コードを簡素化し、Reactアプリケーションのパフォーマンスを向上させることができます。効果を使用する理由を再評価することで、より明確なコンポーネントを作成し、依存関係の設定ミスに関連するエラーを避けることができます。重要なのは、副作用なしでニーズを満たすために、状態、派生値、またはuseMemo
で十分なケースを特定することです。
1import { useState, useEffect } from "react";
2
3interface CartItem {
4 price: number;
5}
6
7interface CartProps {
8 items: CartItem[];
9}
10
11function Cart({ items }: CartProps) {
12 const [total, setTotal] = useState<number>(0);
13
14 useEffect(() => {
15 setTotal(items.reduce((sum, item) => sum + item.price, 0));
16 }, [items]);
17
18 return <p>Total: ${total}</p>;
19}