1
头图

The text starts here~

Overview

The "Rendered more hooks than during the previous render" error is generated when we conditionally call a hook or return early before all hooks have run. To fix this error, move all hooks to the top level of function components and don't use hooks in conditions.

rendered-more-hooks-than-during-previous-render.png

Here is an example to show how the error occurs.

 // App.js

import {useEffect, useState} from 'react';

export default function App() {
  const [counter, setCounter] = useState(0);

  // ⛔️ Error: Rendered more hooks than during the previous render.
  if (counter > 0) {
    // 👇️ calling React hook conditionally
    useEffect(() => {
      console.log('hello world');
    });
  }

  return (
    <div>
      <button onClick={() => setCounter(counter + 1)}>toggle loading</button>
      <h1>Hello world</h1>
    </div>
  );
}

The problem with the code is that we conditionally call the useEffect hook.

top-level call

To fix the bug, we have to move the condition inside the hook. Because React hooks can only be called at the top level.

 import {useEffect, useState} from 'react';

export default function App() {
  const [counter, setCounter] = useState(0);

  // ✅ hook is called at top level (not conditionally)
  useEffect(() => {
    if (counter > 0) {
      console.log('hello world');
    }
  });

  return (
    <div>
      <button onClick={() => setCounter(counter + 1)}>toggle loading</button>
      <h1>Hello world</h1>
    </div>
  );
}

We moved the if statement inside the useEffect hook.

This solves the error because we have to make sure that every time the component renders, the React hooks are called in the same order.

This means we are not allowed to use hooks in loops, conditionals or nested functions.

Here is another example to show how the error occurs.

 import {useState} from 'react';

export default function App() {
  const [counter, setCounter] = useState(0);

  // 👇️ this returns before second hook runs if condition is met
  if (counter > 0) {
    return <h2>Returning early</h2>;
  }

  // ⛔️ Error because hook is called conditionally
  const [color, setColor] = useState('salmon');

  return (
    <div>
      <button onClick={() => setCounter(counter + 1)}>toggle loading</button>
      <h1>Hello world</h1>
    </div>
  );
}

The problem is that the second useState hook will only be called if the above condition is not met.

on condition

To fix this error, move all hooks to the top level of the component, above any conditions that might return a value.

 import {useState} from 'react';

export default function App() {
  const [counter, setCounter] = useState(0);

  const [color, setColor] = useState('salmon');

  // 👇️ condition that may return early must be below all hooks
  if (counter > 0) {
    return <h2>Returning early</h2>;
  }

  return (
    <div>
      <button onClick={() => setCounter(counter + 1)}>toggle loading</button>
      <h1>Hello world</h1>
    </div>
  );
}

We move the second useState hook to the if condition that has the potential to return a value.

This is helpful because the hook is now at the top level and has predictable behavior, allowing React to properly save state between calls to useState and useEffect .

As the documentation says:

  • Only call Hooks from React function components or custom hooks
  • Only use hooks at the top level
  • Don't call Hooks in loops, conditionals or nested functions
  • Make sure to always use Hook at the top level of your React function and before any return

This helps React preserve the state of the hook across multiple useState and useEffect calls.


chuck
300 声望41 粉丝