本质上,我在Next.js应用程序中为两个页面(即profile
和dashboard
(创建了一个HOC,两个页面阻止用户在未经授权的情况下访问它们。
示例:pages/profile.js
import withAuth from "../components/AuthCheck/index";
function Profile() {
return (
<>
<h1>Profile</h1>
</>
)
}
export default withAuth(Profile);
我的Auth组件/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和Adrian提到的内容,我根据它们所包含的内容重读了Next.js文档,总是很好地进行刷新。
话虽如此,我还是尝试了阿甸发布的内容。
在_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时,你会得到<Loader/>
,当为false时,你就会得到下一个要踢的三元;
如果auth
和!user
道具都为true,则会渲染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将在构建时使用道具预渲染此页面由getStaticProps返回。
因此,当在_app
中达到pageProps.auth && !user
时,这就是auth
的来源。
最后两件事:
您需要MyApp
组件中的这个useEffect
函数,它的依赖项中有来自钩子的user
道具。因为这将使URL
在重定向之间保持同步/正确。
在/pages/_app
中,MyApp
添加:
useEffect(() => {
router.replace(router.pathname, undefined, { shallow: true })
}, [user]);
在AuthLogin
组件中添加:
useEffect(() => {
router.replace('/login', undefined, { shallow: true })
}, []);
这样可以确保在呈现组件时,URL是正确的。
我确信,如果你的页面经常更改,你将不得不查看getServerSideProps,但为此解决了我的静态页面用例!
谢谢Juliomalves和Adrian!
我会考虑在需要验证的页面上使用getServerSideProps,看看getServerSideProps。它将在每个请求的一个页面上运行服务器端。
或者,在_app
中呈现身份验证组件可能是有意义的(取决于您的项目设置,尤其是如果您可以访问_app.tsx_
中的身份验证状态(。更具体地说,您可以向auth-wall后面的页面添加protected:true
道具(使用静态道具(。然后在应用程序中,您可以检查特定页面是否已保护===true,如果用户未通过身份验证,则重定向到身份验证组件,例如:
{pageProps.protected && !user ? (
<LoginComponent />
) : (
<Component {...pageProps} />
)}