From React documentation:

Always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls.

React is relying on the order of the Hook calls to know which local state matches which Hook call. That is why it’s important that the Hooks are not called inside loops, conditions, or nested functions.

Also this rule ensures that the Hooks are called only from React function components or custom Hooks so that the stateful logic of a component is clearly visible from its source code.

Noncompliant Code Example

function Profile() {
  const [ordersCount, setOrdersCount] = useState(0);
  if (ordersCount !== 0) {
    useEffect(function() { // Noncompliant, this Hook is called conditionally
      localStorage.setItem('ordersData', ordersCount);
    });
  }

  return <div>{ getName() }</div>
}

function getName() {
  const [name] = useState('John'); // Noncompliant, this Hook is called from simple JavaScript function
  return name;
}

Compliant Solution

function Profile() {
  const [ordersCount, setOrdersCount] = useState(0);
  useEffect(function() {
    if (ordersCount !== 0) {
      localStorage.setItem('ordersData', ordersCount);
    }
  });

  const [name] = useState('John');
  return <div>{ name }</div>
}

See