5

The first rule of Hooks is to only call hooks at the top level, i.e. "Don’t call Hooks inside loops, conditions, or nested functions". The docs explains pretty clearly with an example for calling Hooks inside conditions, but not for the other two cases: loops and nested functions.

Are there examples where something can go wrong when calling Hooks inside loops and nested functions? Moreover, isn't a custom hook just a nested function?

The provided answers for these two related questions here and here unfortunately only give the correct examples.

Glenn Mohammad
  • 3,871
  • 4
  • 36
  • 45

1 Answers1

5

Example of variable-length loop:

const {useState} = React

const WrongLoop = () => {
  const [count, setCount] = useState(1)
  for (let i = 0; i < count; i++) {
    const [x, setX] = useState(i)
  }
  const [unknownOrder, setUnknownOrder] = useState('some state')
  
  return <button onClick={() => setCount(c => c+ 1)}>{count} {unknownOrder}</button>
}

ReactDOM.render(<WrongLoop />, document.getElementById('root'))
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

Example of nested function that would be hard to detect by eslint (custom hooks are a special case - when using the use... prefix in function name, it's usage in the component can be statically analyzed by eslint):

const {useState} = React

const fn = () => {
  const [x, setX] = useState() // is it OK to use hooks unconditionally here?
}

const WrongFn = () => {
  const [count, setCount] = useState(1)
  if (count === 1) {
    fn() // OK to use normal functions conditionally.. but what if there's a hook inside?
  }
  const [unknownOrder, setUnknownOrder] = useState('some state')
  
  return <button onClick={() => setCount(c => c+ 1)}>{count} {unknownOrder}</button>
}

ReactDOM.render(<WrongFn />, document.getElementById('root'))
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>
Aprillion
  • 21,510
  • 5
  • 55
  • 89
  • Thank you for the examples! :) But don't you think the nested function example would also be easily caught by ESLint because it violates rule #2 ([Only Call Hooks from React Functions](https://reactjs.org/docs/hooks-rules.html#only-call-hooks-from-react-functions))? – Glenn Mohammad Oct 26 '19 at 13:03
  • 1
    both examples are caught by ESLint rules, not sure what is your point... you were asking `isn't a custom hook just a nested function?` and I tried to illustrate that no, it isn't, because for a custom hook, the ESLint rule would be able to detect usage of a custom hook inside `if`. but for a regular function, it's OK to use a regular function inside `if`, so they had to make it NOT OK to use a hook inside a regular function – Aprillion Oct 27 '19 at 09:48
  • 1
    Gotcha. My point is the two rules (for the "nested functions" part) boil down to: **Don’t call Hooks inside nested functions unless the nested functions are either React function components or custom Hooks.** Correct? Anyway, I'm already satisfied your answer, so thanks again! – Glenn Mohammad Oct 27 '19 at 10:52