title: How to use useRouter properly while staying within the rules of hook?
body: <p><strong>TLDR / Open Question:</strong></p>
  <pre><code>function LoginForm() {
      const router = useRouter();
  
      async function submitHandler(event) {
          const found = await tryToLogin();
          if (found) {
              // useRouter().push(&quot;/profile&quot;);              // &lt;--- line 1
              // router.push(&quot;/profile&quot;);                   // &lt;--- line 2
          }
      }
      
      return (
          &lt;&gt;
              &lt;form onSubmit={submitHandler}&gt;
                  &lt;inputComponent for username&gt;
                  &lt;inputComponent for password&gt;
                  &lt;button&gt;Login&lt;/button&gt;
              &lt;/form&gt;
          &lt;/&gt;
      );
  }
  </code></pre>
  <p>When line 1 is uncommented and page/component loaded, I get Invalid hook call error, talking about violation of Rules of Hook. That makes sense to me, since hooks need to be called in top level function.</p>
  <p>However, when line 2 is uncommented and run (instead of line 1), there is no error. Why? How is this not violating the rule? Obviously storing the reference to the function in 'router' variable is somehow bypassing the rule, so is it that by calling useRouter() in top level and setting to a variable, i am no longer &quot;calling&quot; it when i access it via the variable on line 2?</p>
  <p>The above code is part of component called on login page. The code in the page's js file checks if the user is already signed in. If so, it simply redirects to another page. If user is not signed in, it loads the above LoginForm. In the login form component, the user enters username/password combo, and hits submit button. That's when the above submitHandler function runs.
  I have the code running and working fine, as expected. I am simply trying to understand why line 1 results in violation and line 2 does not.</p>
  <p><strong>Original Questions</strong></p>
  <p>Scenario: I am trying to use useRouter to move from a login page to a profile page upon successful login. If not, it stays on the page and shows errors etc...</p>
  <p>Now, I have it working fine, but I was trying to improve the code and ran into a confusing situation that I cannot explain. I am a backend engineer primarily, so still learning react, and thus, not sure what is going on...</p>
  <p>Please bare with me as I explain the scenario I am running into. I have the following code (for clarity purposes, just pointing out the essentials):</p>
  <pre><code>function LoginForm() {
      const router = useRouter();
      const [userFound, setUserFound] = useState(false);
  
      console.log(&quot;Alpha&quot;);                     // Alpha
  
      useEffect( () =&gt; {
          console.log(&quot;Bravo&quot;);                 // Bravo
  
          if (userFound) {
              console.log(&quot;Charlie&quot;);           // Charlie
              router.push(&quot;/profile&quot;);
          }
  
          return () =&gt; {
              console.log(&quot;Zulu&quot;);              // Zulu
          };
      }, [userFound]);
  
      async function submitHandler(event) {
          console.log(&quot;Delta&quot;);                 // Delta
          const found = await tryToLogin();
          if (found) {
              console.log(&quot;Epsilon&quot;);           // Epsilon
              // useRouter().push(&quot;/profile&quot;);              // &lt;--- line 1
              // router.push(&quot;/profile&quot;);                   // &lt;--- line 2
              // setUserFound(true);                        // &lt;--- line 3
              console.log(&quot;Fulcrum&quot;);           // Fulcrum
          }
      }
  }
  </code></pre>
  <p><strong>Only Line 1 Uncommented and Running</strong>: When I sign in, it errors out complaining about Invalid hook call. Rules of hooks violation etc... That makes sense to me. You need to call useRouter in topLevel.</p>
  <p><strong>Only Line 2 Uncommented and Running</strong>: This code runs fine. When I login, the user is found, and it sends me to the profile page. I get the following chain of console messages as well:</p>
  <pre><code>Alpha Bravo (first pass)
  (submit clicked)
  Delta Alpha Zulu Epsilon Fulcrum
  </code></pre>
  <p><em>Question 1:</em> How is this not violating the rule? Obviously storing the reference to the function in 'router' variable is somehow bypassing the rule, so is it that by calling useRouter() in top level and setting to a variable, i am no longer &quot;calling&quot; it when i access it via the variable on line 2?</p>
  <p><s><em>Question 2:</em> Why do i see ZULU ahead of EPSILON and FULCRUM ?  I suspect its some form of react hook chaining thing, but I am not really sure, nor do I understand it. Could someone explain or point to a good resource about it?</s></p>
  <p><strong>Only line 3 uncommented and running</strong>: Now, this is where things get interesting. Based on reading around, this is ideally how things should be coded. The submit handler makes a state change, and the useEffect acts on the state changes and does things. However, this does not take me to the profile page. Instead, it takes me to the home page (&quot;/&quot;) and I am not sure why or how it does that! Even the console logs are the same as when running line 2.</p>
  <pre><code>Alpha Bravo (first pass)
  (submit clicked)
  Delta Alpha Zulu Epsilon Fulcrum
  </code></pre>
  <p><s><em>Question 3:</em> Why is line 3 not working as one would expect? Or is my expectation wrong? My expectation (or understanding): if found is true, then we log &quot;epsilon&quot;, set the 'userFound' state to true, and log &quot;fulcrum&quot;. This would trigger a repass of the component because of state change. The useEffect would trigger since 'userFound' is a dependency. It would log 'charlie', and then route push '/profile'. This would trigger the unmounting of this component, and that should fire the cleanup and log 'Zulu'.</s></p>
  <p>Disclaimer:</p>
  <ol>
  <li>As I mentioned, I am still learning react. So, my understanding could be very wrong here, and I would appreciate if you point out how/why.</li>
  <li>Sorry about the question title. I wasn't really sure how to frame it properly.</li>
  </ol>
  <p>EDIT 1:
  I have commented out question 2 and 3, thank to @rossAllen's comments below. I am calling the LoginForm inside a nextjs page, where I have a few other hooks (useSession and useEffect).
  It looks like that while I am waiting for the &quot;tryToLogin&quot; code to return, the useSession actually wins the race condition and gets the session/user, and that triggers the page's rendering and useEffects to fire first. That causes the LoginForm to unmount, and thereby throwing the spanner in the entire model.</p>
  <p>EDIT 2:
  Modified the post so that the only open question about hooks is at the top.</p>