<p dir="auto">As reported in <a href="https://blog.discordapp.com/lessons-from-migrating-a-large-codebase-to-react-16-e60e49102aa6" rel="nofollow">https://blog.discordapp.com/lessons-from-migrating-a-large-codebase-to-react-16-e60e49102aa6</a>, it could've been clearer.</p>
<p dir="auto"><strong>Do you want to request a <em>feature</em> or report a <em>bug</em>?</strong> bug</p>
<p dir="auto"><strong>What is the current behavior?</strong></p>
<p dir="auto">The following piece of code breaks the rules of hooks:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import {useState} from 'react';
const MyComponent = () =&gt; {
  const [foo, setFoo] = useState ();
  if ( !foo ) return;
  const [bar, setBar] = useState ();
  return null;
};"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-kos">{</span><span class="pl-s1">useState</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'react'</span><span class="pl-kos">;</span>
<span class="pl-k">const</span> <span class="pl-smi">MyComponent</span> <span class="pl-c1">=</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
  <span class="pl-k">const</span> <span class="pl-kos">[</span><span class="pl-s1">foo</span><span class="pl-kos">,</span> <span class="pl-s1">setFoo</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-en">useState</span> <span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">if</span> <span class="pl-kos">(</span> <span class="pl-c1">!</span><span class="pl-s1">foo</span> <span class="pl-kos">)</span> <span class="pl-k">return</span><span class="pl-kos">;</span>
  <span class="pl-k">const</span> <span class="pl-kos">[</span><span class="pl-s1">bar</span><span class="pl-kos">,</span> <span class="pl-s1">setBar</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-en">useState</span> <span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">return</span> <span class="pl-c1">null</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">The lint rule reports:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="React Hook &quot;useState&quot; is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return?"><pre class="notranslate"><code class="notranslate">React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return?
</code></pre></div>
<p dir="auto"><strong>What is the expected behavior?</strong></p>
<p dir="auto">My understanding is that for hooks to work they need to be called always in the same order, otherwise returned values can't be properly mapped to function calls.</p>
<p dir="auto">In my piece of code the hooks are always called in the same order, but some times we exit early, which is slightly beneficial both for performance and for writing clean code.</p>
<p dir="auto">Shouldn't this just work?</p>
<p dir="auto"><strong>Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?</strong> v16.8.6</p>