MeWrite Docs

React Hook is called conditionally or in a loop

ReactでHooksのルールに違反した場合のエラー

概要

Reactの Hooks は特定のルールに従って使用する必要があります。条件分岐やループ内で呼び出すとエラーになります。

エラーメッセージ

React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.
React Hook "useEffect" is called in a loop. React Hooks must be called at the top level of the function body.

Hooksのルール

  1. トップレベルでのみ呼び出す - ループ、条件分岐、ネストされた関数内で呼び出さない
  2. React関数からのみ呼び出す - 通常のJavaScript関数からは呼び出さない

NGパターンと修正

1. 条件分岐内でのHooks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// NG
function Component({ isLoggedIn }) {
  if (isLoggedIn) {
    const [user, setUser] = useState(null);  // エラー
  }
  return <div>...</div>;
}

// OK
function Component({ isLoggedIn }) {
  const [user, setUser] = useState(null);  // 常にトップレベル

  if (!isLoggedIn) {
    return <div>Please login</div>;
  }
  return <div>{user?.name}</div>;
}

2. 早期リターン後のHooks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// NG
function Component({ data }) {
  if (!data) {
    return <div>Loading...</div>;
  }
  const [state, setState] = useState(data);  // エラー
  return <div>{state}</div>;
}

// OK
function Component({ data }) {
  const [state, setState] = useState(null);

  if (!data) {
    return <div>Loading...</div>;
  }
  return <div>{state || data}</div>;
}

3. ループ内でのHooks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// NG
function Component({ items }) {
  items.forEach(item => {
    const [checked, setChecked] = useState(false);  // エラー
  });
}

// OK: 子コンポーネントに分離
function Component({ items }) {
  return items.map(item => (
    <ItemComponent key={item.id} item={item} />
  ));
}

function ItemComponent({ item }) {
  const [checked, setChecked] = useState(false);  // OK
  return <div>{item.name}</div>;
}

4. コールバック内でのHooks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// NG
function Component() {
  const handleClick = () => {
    const [count, setCount] = useState(0);  // エラー
  };
}

// OK
function Component() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
  };
}

5. 動的なuseEffect依存

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// NG: 条件によってuseEffectをスキップ
function Component({ shouldFetch }) {
  if (shouldFetch) {
    useEffect(() => {
      fetchData();
    }, []);
  }
}

// OK: useEffect内で条件分岐
function Component({ shouldFetch }) {
  useEffect(() => {
    if (shouldFetch) {
      fetchData();
    }
  }, [shouldFetch]);
}

ESLint設定

1
npm install eslint-plugin-react-hooks --save-dev
1
2
3
4
5
6
7
8
// .eslintrc
{
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn"
  }
}

関連エラー

関連エラー

React の他のエラー

最終更新: 2025-12-17