【问题标题】:Next.js: How to prevent flash of the Unauthorized route/page prior to redirect when implementing a private route?Next.js:在实现私有路由时,如何在重定向之前防止未经授权的路由/页面的闪烁?
【发布时间】:2022-01-14 18:13:44
【问题描述】:

基本上,我在我的 Next.js 应用程序(即profiledashboard)中为两个页面创建了一个 HOC,如果用户未经授权,两个页面将阻止他们访问它们。

示例:pages/profile.js

import withAuth from "../components/AuthCheck/index";

function Profile() {
  return (
    <>
      <h1>Profile</h1>
    </>
  )
}


export default withAuth(Profile);

我的身份验证组件/HOC:

import { useRouter } from 'next/router'
import { useUser } from '../../lib/hooks'
import { PageLoader } from '../Loader/index'

const withAuth = Component => {
  const Auth = (props) => {
    const { isError } = useUser(); //My hook which is calling /api/user see if there is a user
    const router = useRouter()


    if (isError === 'Unauthorized') {
      if (typeof window !== 'undefined' && router.pathname === '/profile' || router.pathname === 'dashboard') router.push('/login')

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

  };

  if (Component.getInitialProps) {
    Auth.getInitialProps = Component.getInitialProps;
  }

  return Auth;
};

export default withAuth;

现在发生的情况是,如果您碰巧在浏览器 URL 栏中输入 /profile/dashboard,在重定向之前您会看到页面一秒钟,即闪烁。

知道为什么会这样吗?

【问题讨论】:

  • 因为重定向发生在客户端 - 在它发生之前,您将首先在服务器上看到生成的页面。防止它的唯一方法是在服务器端重定向。
  • @juliomalves 很有趣。谢谢。那么你会把这个逻辑放在哪里呢?

标签: reactjs next.js higher-order-components next-router


【解决方案1】:

我会考虑在需要验证的页面上使用 getServerSideProps,看看 getServerSideProps 。它会在每个请求的页面上运行服务器端。

或者,在_app 中呈现身份验证组件可能是有意义的(取决于您的项目设置 - 特别是如果您可以访问_app.tsx_ 中的身份验证状态)。更具体地说,您可以将protected:true 属性添加到身份验证墙后面的页面(使用static props)。然后在 app 中,您可以检查特定页面是否已 protected===true 并在用户未通过身份验证时重定向到身份验证组件,例如:

            {pageProps.protected && !user ? (
                <LoginComponent />
            ) : (
              <Component {...pageProps} />
            )}

【讨论】:

  • 感谢阿德里安,您的帖子已解决帮助解决了问题!
【解决方案2】:

根据 Juliomalves 和 Adrian 提到的内容,我重新阅读了 Next.js 文档,基于其中包含的内容,总能得到更新。

话虽如此,我尝试了 Adian 发布的内容。

_app.js 文件中,我执行了以下操作:

import dynamic from "next/dynamic";
import { useRouter } from 'next/router'

import { useEffect } from 'react';

import { PageLoader } from '../components/Loader/index'

import { useUser } from '../lib/hooks'

import Login from '../pages/login'

const Layout = dynamic(() => import('../components/Layout'));

function MyApp({ Component, pageProps }) {
  const { user, isLoading } = useUser();
  const router = useRouter();

  useEffect(() => {
    router.replace(router.pathname, undefined, { shallow: true })
  }, [user])

  function AuthLogin() {
    useEffect(() => {
      router.replace('/login', undefined, { shallow: true })
    }, [])
    return <Login />
  }

  return (
          <Layout>
            {isLoading ? <PageLoader /> :
              pageProps.auth && !user ? (
                <AuthLogin />
              ) : (
                <Component {...pageProps} />
              )
            }
          </Layout>

  );
}

export default MyApp

因此,来自 SWR 钩子 useUser()isLoading 属性是第一个条件三元组的一部分,如果为 true,您将获得 &lt;Loader/&gt;,如果为 false,您将获得下一个三元组;

如果auth!user 属性都为真,则AuthLogin 被渲染!

我就是这样做的。我进入了我想要私有的页面并使用了异步函数 getStaticProps 并创建了 prop auth 并将其设置为 true

/pages/dashboard.jsOr whatever you want to be private;

export default function Dashboard() {
  return (
    <>
      <h1>Dashboard</h1>
    </>
  )
}

export async function getStaticProps() {
  return {
    props: {
      auth: true
    },
  }
}

所以回到_app.js,当页面被渲染时,getStaticProps 将会,正如文档所说所说:

Next.js 将在构建时使用道具预渲染此页面 由 getStaticProps 返回。

所以当_app 到达pageProps.auth &amp;&amp; !user 时,这就是auth 的来源。

最后两件事:

您需要 MyApp 组件中的 useEffect 函数,并在其依赖项中使用来自钩子的 user 属性。因为这将使URL 在重定向之间保持同步/正确。

/pages/_appMyApp 中添加:

 useEffect(() => {
    router.replace(router.pathname, undefined, { shallow: true })
  }, [user]);

AuthLogin组件中添加:

 useEffect(() => {
      router.replace('/login', undefined, { shallow: true })
    }, []);

这样可以确保在渲染组件时,URL 是正确的。

我确定如果您的页面经常更改,您将不得不查看getServerSideProps,但这解决了我的静态页面用例!

感谢 Juliomalves 和 Adrian!

【讨论】:

    猜你喜欢
    • 2021-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-07
    • 2020-12-20
    • 1970-01-01
    • 2012-07-22
    • 2021-06-18
    相关资源
    最近更新 更多