在 useEffect 内部,当刷新页面时,两个条件分支都会被触发。

huangapple go评论67阅读模式
英文:

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

问题

这是 React 组件中的 useEffect 代码。

  import { useSession } from '@supabase/auth-helpers-react'
  const session = useSession()
  useEffect(() => {
    if (session) {
      console.debug('保持在页面')
    } else {
      console.debug('转到登录')
      router.push('/login').then(
        () => {
          console.debug('转到登录完成')
        }
      )
    }
  }, [session, router])

它使用 Supabase 管理身份验证(会话)。

在刷新页面时,它存在一个非常奇怪的问题(通过路由进行的登录、登出重定向完全没有问题,只有在刷新页面时才有问题)。两个分支都会被触发,所以在 js 控制台中,我们可以看到两个条件分支的日志。

'保持在页面''转到登录'/ '转到登录完成'

我假设这是因为刷新后 session 发生了变化。第一次是未定义的,立即触发第二个分支 router.push,在找到会话时触发第一个分支 保持在页面

是否有任何建议可以绕过这个问题?或者有关于在 React/NextJS 中处理页面刷新的良好实践?还有谁之前遇到过类似或相同的问题吗?

英文:

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?

答案1

得分: 1

在你的代码中,当 session 或 router 的值发生变化时,useEffect 将被执行(useEffect 的第二个参数)。因此,ifelse 不会在同一次 useEffect 执行中被同时执行,尽管它们可能在快速连续的两次执行中被执行。

以下是实现你想要的方式之一:

  1. 使用 useState 创建和管理一个变量的状态。
  2. useEffect 中,通过应用逻辑来设置状态(或不设置状态)以检查 session。
  3. 在返回语句中,要么渲染当前页面,要么显示登录页面。

一个示例实现:

const App = (props) => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  
  useEffect(() => {
    // 应用逻辑并设置状态
    if (logic) setIsLoggedIn(true);
  }, []);
  
  return isLoggedIn ? <ActiveApp /> : <Login />;
}
英文:

In your code, useEffect will be executed whenever value for session or router changes (the 2nd parameter to useEffect). Hence, both if and else are not being executed in the same run of useEffect, albeit, in two different runs that are executed perhaps in quick succession.

Here is one way of achieving what you are after.

  1. Create and manage the state of a variable using useState
  2. In the useEffect, set the state (or not) by applying logic to check session
  3. In the return either render the current page or show the login page.

A sample implementation:

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

}

答案2

得分: 0

终于,我找到了这个问题的根本原因。

这是来自于supabase auth helperuseSession 钩子,它是一个异步函数,不包括它是否正在加载或出错的状态,这意味着在开始时它将始终为null(这意味着它正在加载)。

解决这个问题的简单方法是,直接使用 useSessionContextsession 仍然会以异步方式获取,但 isLoadingerror 状态可以以同步方式获取,以解决这个问题,并且它们可以用于 useEffect 中的条件分支。

新的代码将如下所示:

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

    if (isLoading) {
      console.debug('显示加载页面')
    }
    else if (session) {
      console.debug('保持在页面上')
    } 
    else {
      console.debug('跳转到登录页')
      router.push('/login').then(
        () => {
          console.debug('跳转到登录完成')
        }
      )
    }
  }, [session, isLoading, router])
英文:

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 &#39;@supabase/auth-helpers-react&#39;
  const {isLoading, session} = useSessionContext()
  useEffect(() =&gt; {

    if (isLoading) {
      console.debug(&#39;show loading page&#39;)
    }
    else if (session) {
      console.debug(&#39;stay in page&#39;)
    } 
    else {
      console.debug(&#39;goto login&#39;)
      router.push(&#39;/login&#39;).then(
        () =&gt; {
          console.debug(&#39;goto login done&#39;)
        }
      )
    }
  }, [session, isLoading, router])

huangapple
  • 本文由 发表于 2023年6月13日 18:56:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76464195.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定