Search code examples
reactjsnext.jsreact-hooksfrontendsupabase

Inside of useEffect, both condition branches got triggered when refresh page


This is the useEffect code in the React component.

  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])

It uses a supabase to manage auth (session).

It has a very weid issue when refresh page, (login, logout redirect through router has no issues at all, only when Refresh page.), both branches will be reached, so in js console, we could see logs from both condition branches.

'stay in page' and goto login/ goto login done.

I assume it is due to session changed after refresh. 1st time is undefined, to trigger the 2nd brach router.push, immediately, when session be found, triggers the 1st branch stay in page.

Is there any suggestion to bypass it? Or any good practice to handle page refresh in React/NextJS? Or anyone has similar or the same issue before?


Solution

  • Finally, I got the root cause for this.

    It is from the useSession hook from supabase auth helper, it is an async function, and it does not include the state of whether it is loading or error, which it means it will always be null in the beginning (which it means it is in loading).

    The simple solution to solve it, is to use useSessionContext directly instead. session will still be gotten in an async way, but isLoading and error state can be gotten in a sync way to resolve this issue, and they can be used for condition branching inside useEffect.

    New code will be 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])