Glenn Mohammad
Glenn Mohammad

Reputation: 4705

React: incorrect examples of calling Hooks inside loops and nested functions

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.

Upvotes: 5

Views: 2724

Answers (1)

Aprillion
Aprillion

Reputation: 22324

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>

Upvotes: 5

Related Questions