Next.js: 实现私有路由时,如何防止跳转前出现Unauthorized route/page?
Next.js: How to prevent flash of the Unauthorized route/page prior to redirect when implementing a private route?
基本上,我在我的 Next.js 应用程序中为两个页面(即 profile
和 dashboard
)创建了一个 HOC,这两个页面阻止了未经授权的用户访问它们。
示例:pages/profile.js
import withAuth from "../components/AuthCheck/index";
function Profile() {
return (
<>
<h1>Profile</h1>
</>
)
}
export default withAuth(Profile);
我的授权 component/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
,在重定向之前您将看到该页面一秒钟,即 flash .
知道为什么会这样吗?
我会考虑在需要授权的页面上使用 getServerSideProps,看看 getServerSideProps 。它会 运行 服务器端在每个请求的页面上。
或者,在 _app
中呈现 auth 组件可能有意义(取决于您的项目设置 - 特别是如果您可以访问 _app.tsx_
中的 auth 状态)。更具体地说,您可以将 protected:true
属性添加到 auth wall 后面的页面(使用 static props)。然后在 app 中,您可以检查特定页面是否具有 protected===true 并在用户未被授权时重定向到 auth 组件,例如:
{pageProps.protected && !user ? (
<LoginComponent />
) : (
<Component {...pageProps} />
)}
根据 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
属性是第一个条件三元组的一部分,当为真时你得到 <Loader/>
,当为假时你得到下一个三元组踢;
如果 auth
和 !user
属性都为真,则 AuthLogin
得到渲染!
我就是这样做的。我进入了我想要私有的页面并使用异步函数 getStaticProps 并创建了道具 auth
并将其设置为 true
.
/pages/dashboard.js
Or 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 will pre-render this page at build time using the props
returned by getStaticProps.
所以当 pageProps.auth && !user
在 _app
中达到时,这就是 auth
的来源。
最后两件事:
您需要 MyApp
组件中的此 useEffect
函数及其依赖项中钩子的 user
属性。因为这将在重定向之间将 URL
保留在 sync/correct 中。
在/pages/_app
、MyApp
中添加:
useEffect(() => {
router.replace(router.pathname, undefined, { shallow: true })
}, [user]);
在AuthLogin
组件中添加:
useEffect(() => {
router.replace('/login', undefined, { shallow: true })
}, []);
这确保组件渲染时,URL 是正确的。
我敢肯定,如果您的页面经常更改,您将不得不查看 getServerSideProps 但为此解决了我的静态页面用例!
谢谢 Juliomalves 和 Adrian!
基本上,我在我的 Next.js 应用程序中为两个页面(即 profile
和 dashboard
)创建了一个 HOC,这两个页面阻止了未经授权的用户访问它们。
示例:pages/profile.js
import withAuth from "../components/AuthCheck/index";
function Profile() {
return (
<>
<h1>Profile</h1>
</>
)
}
export default withAuth(Profile);
我的授权 component/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
,在重定向之前您将看到该页面一秒钟,即 flash .
知道为什么会这样吗?
我会考虑在需要授权的页面上使用 getServerSideProps,看看 getServerSideProps 。它会 运行 服务器端在每个请求的页面上。
或者,在 _app
中呈现 auth 组件可能有意义(取决于您的项目设置 - 特别是如果您可以访问 _app.tsx_
中的 auth 状态)。更具体地说,您可以将 protected:true
属性添加到 auth wall 后面的页面(使用 static props)。然后在 app 中,您可以检查特定页面是否具有 protected===true 并在用户未被授权时重定向到 auth 组件,例如:
{pageProps.protected && !user ? (
<LoginComponent />
) : (
<Component {...pageProps} />
)}
根据 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
属性是第一个条件三元组的一部分,当为真时你得到 <Loader/>
,当为假时你得到下一个三元组踢;
如果 auth
和 !user
属性都为真,则 AuthLogin
得到渲染!
我就是这样做的。我进入了我想要私有的页面并使用异步函数 getStaticProps 并创建了道具 auth
并将其设置为 true
.
/pages/dashboard.js
Or 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 will pre-render this page at build time using the props returned by getStaticProps.
所以当 pageProps.auth && !user
在 _app
中达到时,这就是 auth
的来源。
最后两件事:
您需要 MyApp
组件中的此 useEffect
函数及其依赖项中钩子的 user
属性。因为这将在重定向之间将 URL
保留在 sync/correct 中。
在/pages/_app
、MyApp
中添加:
useEffect(() => {
router.replace(router.pathname, undefined, { shallow: true })
}, [user]);
在AuthLogin
组件中添加:
useEffect(() => {
router.replace('/login', undefined, { shallow: true })
}, []);
这确保组件渲染时,URL 是正确的。
我敢肯定,如果您的页面经常更改,您将不得不查看 getServerSideProps 但为此解决了我的静态页面用例!
谢谢 Juliomalves 和 Adrian!