Inside useEffect, two conditional branches are triggered when the page is refreshed
P粉798343415
P粉798343415 2023-09-03 14:09:00
0
2
636
<p>This is the <code>useEffect</code> code in the React component. </p> <pre class="brush:js;toolbar:false;"> import { useSession } from '@supabase/auth-helpers-react' const session = useSession() useEffect(() => { if (session) { console.debug('stay in page') } else { console.debug('goto login') router.push('/login').then( () => { console.debug('goto login done') } ) } }, [session, router]) </pre> <p>It uses supabase to manage authentication (session). </p> <p>There is a very strange problem when refreshing the page (there is no problem at all with login and logout redirection through the router, it only appears when the page is refreshed.), both branches will be reached, so in the js console, we can see Log conditional branch from two branches. </p> <p><code>"Stay on page"</code> and <code>Go to login</code>/<code>Go to login complete</code>. </p> <blockquote> <p>I think this is due to the <code>session</code> changing after the refresh. The first time it is undefined, the second branch <code>router.push</code> is triggered. When the session is found, the first branch <code>stays on the page</code> is triggered immediately. </p> </blockquote> <p>Any suggestions on how to get around it? Or are there any <strong>good practices</strong> for handling page refreshes in React/NextJS? Or has anyone encountered similar or the same problem before? </p>
P粉798343415
P粉798343415

reply all(2)
P粉276876663

In your code, useEffect will be executed whenever the value of the session or router changes (the second parameter of useEffect). Therefore, neither if nor else are executed in the same run of useEffect, although they are executed in two different runs that may be executed in rapid succession.

This is one way to achieve what you are after.

  1. Use useState to create and manage the state of variables
  2. In useEffect, set (or not set) the state by applying logic to check the session
  3. Render the current page or display the login page in the return.

Example implementation:

const App = (props) => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  
  useEffect(()=>{
    //apply the logic and set the state
    if(logic) setIsLoggedIn(true);
  },[]) 
  
  return  {isLoggedIn ? <ActiveApp /> : <Login />}

}
P粉035600555

Finally, I found the root cause.

It comes from the supabase auth helper, it is an async function, it does not contain the status of whether it is loading or wrong, which means it is at the beginning (which means it is loading).

The simple way to solve this problem is to use directly useSessionContext. session will still be fetched asynchronously, but the isLoading and error statuses can be fetched synchronously to resolve this issue, and they can be used with useEffect# Conditional branches within ##.

The new code will look like this:

  import { useSessionContext } from '@supabase/auth-helpers-react'
  const {isLoading, session} = useSessionContext()
  useEffect(() => {

    if (isLoading) {
      console.debug('show loading page')
    }
    else if (session) {
      console.debug('stay in page')
    } 
    else {
      console.debug('goto login')
      router.push('/login').then(
        () => {
          console.debug('goto login done')
        }
      )
    }
  }, [session, isLoading, router])

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template