BLOG

ブログ

よくあるReactエラーを5秒で直したい

Each child in a list should have a unique “key” prop

原因:mapにkeyをつけてない

対処:一意なIDやインデックスをkeyに設定する

const Component = () => {
  const users = ["山田", "田中", "鈴木"];
  return (
    <ul>
      {users.map((user, index) => <li key={index}>{user}</li>)} // ←keyにindexまたは一意のidなどを付与すること
    </ul>
  );
};

mapで繰り返す要素には、Reactが差分を認識できるように key を必ず付ける
→ 基本はIDなどの一意な値、なければ配列のインデックスでもOK。

Cannot read property ‘xxx’ of undefined

原因:propsやstateがundefinedのままアクセスしている

対処: useEffectやイベントハンドラ内でstate更新を行う

これは初期値を設定する方法

const Component = ({ user = { name: "Guest" } }) => {
  return <p>{user.name}</p>;
};

または、オプショナルチェーン(?.)を使う

const Component = ({ user }) => {
  return <p>{user?.name ?? "Guest"}</p>;
};

→ propsやstateがundefinedになる可能性を考慮する
→ デフォルト値を用意する or ?. を使う

Too many re-renders. React limits the number of renders to prevent an infinite loop

原因: setStateをレンダリング中に直接呼んでいる

対処: useEffectやイベントハンドラ内でstate更新を行う

❌ダメな例

const Component = () => {
  const [count, setCount] = useState(0);

  // レンダリングされるたびにsetCountが呼ばれる → 無限ループ
  setCount(count + 1);

  return <p>{count}</p>;
};

⭕️setStateはイベントハンドラ内で行う。もしくはuseEffectを使う

const Component = () => {
  const [count, setCount] = useState(0);

  return (
    <>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </>
  );
};

// または

const Component = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setCount(c => c + 1); // 初回マウント時や特定のタイミングにのみ実行
  }, []);

  return <p>{count}</p>;
};

→ レンダリング中に直接 setState を書くのはNG
→ 更新は イベントハンドラuseEffect に書く

Invalid hook call. Hooks can only be called inside of the body of a function component.

原因: hookを関数コンポーネントの外や条件分岐の中で呼んでいる

対処: 必ず関数コンポーネント直下で、トップレベルで呼び出す

// コンポーネントの外でuseStateを呼んでしまうとエラー
const [count, setCount] = useState(0); // ❌ これはだめ

const Component = () => {
  const [count, setCount] = useState(0); // ⭕️ コンポーネント内で呼ぶ

  return (
    <>
      <p>{count}</p>
      <button onClick={() => setCount(c => c + 1)}>+1</button>
    </>
  );
}

→ Hooksは関数コンポーネント or カスタムHookのトップレベルでのみ利用可能

A component is changing an uncontrolled input to be controlled

原因: <input>valueを渡したり渡さなかったり不安定

対処: valueonChangeをセットで管理、初期値を設定する

❌ダメな例

const Component = () => {
  const [text, setText] = useState(); // 初期値未設定

  return (
    <input
      value={text} // 最初はundefined(uncontrolled)
      onChange={e => setText(e.target.value)} // 後からcontrolledに
    />
  );
}

value が最初 undefined なので 非制御 (uncontrolled) なのに、途中から setText制御 (controlled) に切り替わってしまうためエラーが出る

⭕️初期値もしくはdefaultValueを使う

const Component = () => {
  const [text, setText] = useState(""); // ⭕️ 初期値を空文字に

  return (
   <>
     <input
      value={text}
      onChange={e => setText(e.target.value)}
     />
     {/* またはdefaultValueによる初期値を設定する */}
     <input defaultValue="山田" />
   </>
  );
}

→ Reactのinputは「controlled(Reactで管理)」か「uncontrolled(DOM)」のどちらかに統一する必要がある
valueを使うなら初期値を何かしら設定して常にcontrolledにする
→ 状態管理不要ならdefaultValueを使ってもよい

RELATED ARTICLE