Supabase Authentication Redirection Flicker in Next.js using HOC w/ useSessionContext

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

Supabase Authentication Redirection Flicker in Next.js using HOC w/ useSessionContext

问题

我在我的Web应用程序中使用Supabase进行身份验证。我注意到,当我已经登录并尝试导航到登录页面进行测试时,它会在重定向到正确的受保护路由之前短暂显示登录页面。尽管使用useSessionContext()设置了isLoading状态,但仍然会发生这种情况。

我期望它在isLoading为true时显示CircularProgress,然后一旦isLoading为false且session为true(表示我已经登录),它就会直接重定向而不显示登录页面。然而,在实际操作中,我看到登录页面在重定向发生之前短暂显示。

在开发模式下,此登录页面可见几秒钟然后重定向。在生产模式下(使用npm start),它更像是一闪而过。为什么会发生这种情况,我如何使其只显示加载中的CircularProgress,然后如果我已经登录就直接重定向?

高阶组件

import CircularProgress from '@mui/material/CircularProgress';
import { useSessionContext } from '@supabase/auth-helpers-react';
import { useRouter } from 'next/router';
import { FC, useEffect } from 'react';
import ErrorIcon from '@mui/icons-material/Error';
import { Typography } from '@mui/material';

export const withAuth = <T extends Record<string, unknown>>(
  Component: FC<T>,
  redirectLink = '/'
) => {
  const AuthenticatedComponent: FC<T> = (props) => {
    const router = useRouter();
    const { isLoading, session, error } = useSessionContext();

    useEffect(() => {
      const checkAuth = async () => {
        if (session) {
          await router.replace(redirectLink);
        }
      };
      checkAuth();
    }, [session, router]);

    if (isLoading) return <CircularProgress color='primary' size={'2rem'} />;

    if (error)
      return (
        <>
          <ErrorIcon color='error' fontSize='large' />
          <Typography variant='body1'>
            We are experiencing technical difficulties. Please try again later.
          </Typography>
        </>
      );

    return <Component {...(props as T)} />;
  };

  return AuthenticatedComponent;
};

登录页面

const LoginPage = () => {
  const supabaseClient = useSupabaseClient();
  return (
    <Box sx={{ width: '50%', padding: '50px' }}>
      <Auth redirectTo='/' appearance={{ theme: ThemeSupa }} supabaseClient={supabaseClient} providers={['google']} socialLayout='horizontal' />
    </Box>
  );
};

export default withAuth(LoginPage);
英文:

I am using Supabase for authentication in my web application. I've noticed that when I'm already logged in and try to navigate to the login page for testing, it briefly shows the login page before redirecting to the correct protected route. This happens despite having an isLoading state set up using useSessionContext().

I expected it to display the CircularProgress while isLoading is true, then, once isLoading is false and session is true (indicating I'm already logged in), it would directly redirect me without showing the login page. However, in practice, I see the login page briefly before the redirection happens.

In development mode, this login page is visible for a few seconds before redirecting. In production mode (using npm start), it's more of a flicker. Why is this happening and how can I make it display only the CircularProgress while loading, then directly redirect if I'm already logged in?

HOC component

import CircularProgress from &#39;@mui/material/CircularProgress&#39;;
import { useSessionContext } from &#39;@supabase/auth-helpers-react&#39;;
import { useRouter } from &#39;next/router&#39;;
import { FC, useEffect } from &#39;react&#39;;
import ErrorIcon from &#39;@mui/icons-material/Error&#39;;
import { Typography } from &#39;@mui/material&#39;;

export const withAuth = &lt;T extends Record&lt;string, unknown&gt;&gt;(Component: FC&lt;T&gt;, redirectLink = &#39;/&#39;) =&gt; {
    const AuthenticatedComponent: FC&lt;T&gt; = (props) =&gt; {
        const router = useRouter();
        const { isLoading, session, error } = useSessionContext();

        useEffect(() =&gt; {
            const checkAuth = async () =&gt; {
                if (session) {
                    await router.replace(redirectLink);
                }
            };
            checkAuth();
        }, [session, router]);

        if (isLoading) return &lt;CircularProgress color=&#39;primary&#39; size={&#39;2rem&#39;} /&gt;;

        if (error)
            return (
                &lt;&gt;
                    &lt;ErrorIcon color=&#39;error&#39; fontSize=&#39;large&#39; /&gt;
                    &lt;Typography variant=&#39;body1&#39;&gt;We are experiencing technical difficulties. Please try again later.&lt;/Typography&gt;
                &lt;/&gt;
            );

        return &lt;Component {...(props as T)} /&gt;;
    };

    return AuthenticatedComponent;
};

Login Page

const LoginPage = () =&gt; {
    const supabaseClient = useSupabaseClient();
    return (
        &lt;Box sx={{ width: &#39;50%&#39;, padding: &#39;50px&#39; }}&gt;
            &lt;Auth redirectTo=&#39;/&#39; appearance={{ theme: ThemeSupa }} supabaseClient={supabaseClient} providers={[&#39;google&#39;]} socialLayout=&#39;horizontal&#39; /&gt;
        &lt;/Box&gt;
    );
};

export default withAuth(LoginPage);

答案1

得分: 0

经过一些调查,我意识到在重定向之前登录页面短暂显示的原因是会话检查和重定向操作都是异步的。因此,在重定向动作发生之前会有一个小的延迟,导致登录页面被呈现出来。

最初,我只在isLoading为true时显示CircularProgress,即在会话检查进行时。然而,似乎这并不足以防止登录页面的短暂显示,因为重定向操作也需要时间来完成。

我已经找到了解决这个问题的方法,即不仅在会话检查期间显示加载旋转器,还在会话存在且即将发生重定向时显示加载旋转器。

我像这样更新了我的代码:

if (isLoading || session) {
    return <CircularProgress color='primary' size={'2rem'} />;
}

现在,在会话检查期间(isLoading为true)和重定向过程中(session为true)都会显示加载旋转器。因此,加载旋转器会一直显示在屏幕上,直到会话检查完成并完成重定向操作。这有效地防止了在重定向之前登录页面在屏幕上短暂闪烁。

英文:

After some investigation, I've realized the brief display of the login page before redirecting is due to both the session check and the redirect operation being asynchronous. As a result, there is a small delay where the login page gets rendered before the redirect action takes place.

Initially, my condition for displaying the CircularProgress was only when isLoading was true, i.e., while the session check was ongoing. However, it seems this wasn't enough to prevent the brief display of the login page, as the redirect operation also needs time to complete.

I've found a solution to this problem by showing the loading spinner not just during the session check, but also when a session is present and a redirect is about to occur.

I updated my code like this:

if (isLoading || session) {
    return &lt;CircularProgress color=&#39;primary&#39; size={&#39;2rem&#39;} /&gt;;
}

Now, the loading spinner is shown during the session check (isLoading is true) and during the redirect process (session is true). As a result, the loading spinner stays on the screen until the session check completes and the redirect operation is finalized. This effectively prevents the login page from briefly flashing on the screen before the redirect.

huangapple
  • 本文由 发表于 2023年5月26日 14:29:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76338161.html
匿名

发表评论

匿名网友

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

确定