React の useState フックは、機能コンポーネントの状態を管理するために不可欠なツールですが、いくつかの一般的な落とし穴に陥りやすいです。 React を使い始めたばかりの場合でも、しばらく React を使用している場合でも、これらの間違いを避けることで、予期しないバグやパフォーマンスの問題を回避できます。
よくある 10 の間違いと、それらを回避してよりクリーンで効率的なコードを作成する方法を見てみましょう。
最も一般的な問題の 1 つは、初期状態のタイプが状態の更新中に予期されるタイプと一致しない場合に発生します。
❌ 間違い: 初期状態の型が一致しません
const [count, setCount] = useState(0); setCount("1"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'.
✅ 解決策: TypeScript を使用するか、型を明示的に指定します。
const [count, setCount] = useState(0); setCount(1); // No issues now.
前の値に基づいて状態を更新する場合、現在の状態を直接参照すると、特に非同期操作で値が古くなる可能性があります。
❌ 間違い: 現在の状態を直接使用しています
setCount(count 1); // Can cause bugs in async scenarios.
✅ 解決策: 安全に更新するには関数型フォームを使用してください。
setCount((prevCount) => prevCount 1); // Ensures you always have the latest value.
他の状態やプロパティから派生する可能性のある値を状態に保存することは避けてください。これにより、不必要な再レンダリングや同期の問題が発生する可能性があります。
❌ 間違い: 派生状態の保存
const [count, setCount] = useState(0); const [doubleCount, setDoubleCount] = useState(count * 2);
✅ 解決策: state.
を使用する代わりに、レンダリング中に値を導出します。
const [count, setCount] = useState(0); const doubleCount = count * 2; // No need to store this in state.
レンダリング フェーズ内で setState を呼び出すと、無限ループとパフォーマンスの問題が発生します。
❌ 間違い: レンダリング中の状態の設定
const [count, setCount] = useState(0); setCount(1); // Infinite loop!
✅ 解決策: イベント ハンドラーまたはエフェクトで状態の変更をトリガーします。
const handleClick = () => setCount(1);
特に配列やオブジェクトで状態を直接変更すると、React は変更を検出しません。
❌ 間違い: 状態を直接変更しました
const [items, setItems] = useState([1, 2, 3]); items.push(4); // Mutation happens here, React won’t re-render!
✅ 解決策: 新しい配列またはオブジェクトを返して、再レンダリングをトリガーします。
setItems((prevItems) => [...prevItems, 4]); // Spread to create a new array.
複雑な状態を扱う場合、適切な型を定義しないと、実行時の問題や混乱が生じる可能性があります。
❌ 間違い: 暗黙的な型はエラーを引き起こす可能性があります
const [user, setUser] = useState({ name: "", age: 0 }); setUser({ name: "John", age: "thirty" }); // Type error: Age should be a number.
✅ 解決策: 正しいタイプで状態の形状を定義します。
type User = { name: string; age: number }; const [user, setUser] = useState({ name: "", age: 0 });
タイマーなどのレンダリングに影響しない値に useState を使用すると、不必要な再レンダリングが発生します。
❌ 間違い: 可変値に状態を使用している
const [timerId, setTimerId] = useState(null);
✅ 解決策: 再レンダリングの必要のない変更可能な値には useRef を使用します。
const timerIdRef = useRef(null);
クラス コンポーネントとは異なり、useState は更新を自動的にマージしません。これを忘れると、状態の一部が上書きされる可能性があります。
❌ 間違い: マージせずに状態を上書きします
const [user, setUser] = useState({ name: '', age: 0 }); setUser({ age: 25 }); // The 'name' field is now lost!
✅ 解決策: スプレッド演算子を使用して状態の更新をマージします。
setUser((prevUser) => ({ ...prevUser, age: 25 })); // Merges with existing state.
状態内のウィンドウの寸法などの高頻度の値を追跡すると、過剰な再レンダリングによりパフォーマンスの問題が発生する可能性があります。
❌ 間違い: 頻繁な更新に状態を使用している
const [size, setSize] = useState(window.innerWidth); window.addEventListener("resize", () => setSize(window.innerWidth));
✅ 解決策: useRef または debounce を使用して、パフォーマンスへの影響を軽減します。
const sizeRef = useRef(window.innerWidth); useEffect(() => { const handleResize = () => { sizeRef.current = window.innerWidth; }; window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, []);
React の状態更新は非同期ですが、多くの開発者は変更がすぐに適用されると誤解しています。
❌ 間違い: 状態の変更が即時であると仮定している
setCount(count 1); console.log(count); // Logs the old value, not the updated one!
✅ 解決策: useEffect を使用して状態の変更を追跡し、最新の値が使用されていることを確認します。
useEffect(() => { console.log(count); // Logs the updated value after re-render. }, [count]);
これらの useState の落とし穴を回避すると、React コードがより堅牢で読みやすく、パフォーマンスが向上します。 React の状態メカニズムがどのように機能するかを理解し、ベスト プラクティスを知ることで、デバッグの時間を節約し、全体的な開発エクスペリエンスを向上させることができます。
useState に関するヒントや間違いを共有できますか?以下のコメント欄に書き込んでください。 ?
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3