レンダリング中に異なるコンポーネントの状態更新を行う時は気を付ける

以下のようなコードがあるとする。

"use client";

import { useState } from "react";

function ParentComponent() {
  const [parentState, setParentState] = useState("initial");

  return (
    <div>
      <h1>Parent State: {parentState}</h1>
      <ChildComponent setParentState={setParentState} />
    </div>
  );
}

function ChildComponent({ setParentState }: { setParentState: (value: string) => void }) {
  // この関数内で親コンポーネントの状態を変更
  setParentState("updated");

  return <div>Child Component</div>;
}

export default ParentComponent;

これを実行すると、以下のようなエラーが出力される。

Cannot update a component (`ParentComponent`) while rendering a different component (`ChildComponent`). To locate the bad setState() call inside `ChildComponent`, follow the stack trace as described in https://react.dev/link/setstate-in-render

これは、ChildComponentのレンダリング中にParentComponentのsetParentStateを直接呼び出し、状態を更新しようと試みたことにより発生したエラーである。
Reactは、レンダリング中に他のコンポーネントの状態更新を禁止している。これを防ぐには、以下のように修正する。

"use client";

import { useEffect, useState } from "react";

function ParentComponent() {
  const [parentState, setParentState] = useState("initial");

  return (
    <div>
      <h1>Parent State: {parentState}</h1>
      <ChildComponent setParentState={setParentState} />
    </div>
  );
}

function ChildComponent({ setParentState }: { setParentState: (value: string) => void }) {
  useEffect(() => {
    // レンダリング後に状態を更新
    setParentState("updated");
  }, [setParentState]);

  return <div>Child Component</div>;
}

export default ParentComponent;

useEffectを使用する事で、ChildComponentのレンダリング後に状態更新されるよう、実行タイミングをコントロールが出来る。

いいなと思ったら応援しよう!