如何使用 HOC 将其重构为“withAuth”?或者可以在 Next.js 中使用 hooks 吗?
How do I refactor this into `withAuth` using HOC? Or is it possible to use hooks here in Next.js?
import { useSession } from 'next-auth/react'
import { LoginPage } from '@/client/components/index'
const Homepage = () => {
const session = useSession()
if (session && session.data) {
return (
<>
<div>Homepage</div>
</>
)
}
return <LoginPage />
}
export default Homepage
基本上,我不想在每一页上都写 Login
和 useSession()
的相同样板文件。
我想要这样的东西:
import { withAuth } from '@/client/components/index'
const Homepage = () => {
return (
<>
<div>Homepage</div>
</>
)
}
export default withAuth(Homepage)
或者如果可能的话withAuthHook
?
我目前做了以下事情:
import React from 'react'
import { useSession } from 'next-auth/react'
import { LoginPage } from '@/client/components/index'
export const withAuth = (Component: React.Component) => (props) => {
const AuthenticatedComponent = () => {
const session = useSession()
if (session && session.data) {
return <Component {...props} />
}
return <LoginPage />
}
return AuthenticatedComponent
}
但是我得到一个错误:
JSX element type 'Component' does not have any construct or call signatures.ts(2604)
如果我使用下面答案中提到的 React.ComponentType
,我会收到一条错误消息:
TypeError: (0 , client_components_index__WEBPACK_IMPORTED_MODULE_0_.withAuth) is not a function
你试过了吗:
export const withAuth = (Component: React.ComponentType) => (props) => {
...
https://flow.org/en/docs/react/types/#toc-react-componenttype
编辑:
像这样尝试:
export const withAuth = (Component: React.ComponentType) => (props) => {
const session = useSession()
if (session && session.data) {
return <Component {...props} />
}
return <LoginPage />
}
return AuthenticatedComponent
}
答案是 hidden in the docs。我必须在 _app.tsx
中指定以下 Auth
函数:
import { useEffect } from 'react'
import { AppProps } from 'next/app'
import { SessionProvider, signIn, useSession } from 'next-auth/react'
import { Provider } from 'urql'
import { client } from '@/client/graphql/client'
import '@/client/styles/index.css'
function Auth({ children }: { children: any }) {
const { data: session, status } = useSession()
const isUser = !!session?.user
useEffect(() => {
if (status === 'loading') return
if (!isUser) signIn()
}, [isUser, status])
if (isUser) {
return children
}
return <div>Loading...</div>
}
interface AppPropsWithAuth extends AppProps {
Component: AppProps['Component'] & { auth: boolean }
}
const CustomApp = ({ Component, pageProps: { session, ...pageProps } }: AppPropsWithAuth) => {
return (
<SessionProvider session={session}>
<Provider value={client}>
{Component.auth ? (
<Auth>
<Component {...pageProps} />
</Auth>
) : (
<Component {...pageProps} />
)}
</Provider>
</SessionProvider>
)
}
export default CustomApp
在我的实际页面上,我必须将 Component.auth
指定为 true
:
const Homepage = () => {
return (
<>
<div>Homepage</div>
</>
)
}
Homepage.auth = true
export default Homepage
上找到关于它的功能的一个很好的总结
import { useSession } from 'next-auth/react'
import { LoginPage } from '@/client/components/index'
const Homepage = () => {
const session = useSession()
if (session && session.data) {
return (
<>
<div>Homepage</div>
</>
)
}
return <LoginPage />
}
export default Homepage
基本上,我不想在每一页上都写 Login
和 useSession()
的相同样板文件。
我想要这样的东西:
import { withAuth } from '@/client/components/index'
const Homepage = () => {
return (
<>
<div>Homepage</div>
</>
)
}
export default withAuth(Homepage)
或者如果可能的话withAuthHook
?
我目前做了以下事情:
import React from 'react'
import { useSession } from 'next-auth/react'
import { LoginPage } from '@/client/components/index'
export const withAuth = (Component: React.Component) => (props) => {
const AuthenticatedComponent = () => {
const session = useSession()
if (session && session.data) {
return <Component {...props} />
}
return <LoginPage />
}
return AuthenticatedComponent
}
但是我得到一个错误:
JSX element type 'Component' does not have any construct or call signatures.ts(2604)
如果我使用下面答案中提到的 React.ComponentType
,我会收到一条错误消息:
TypeError: (0 , client_components_index__WEBPACK_IMPORTED_MODULE_0_.withAuth) is not a function
你试过了吗:
export const withAuth = (Component: React.ComponentType) => (props) => {
...
https://flow.org/en/docs/react/types/#toc-react-componenttype
编辑: 像这样尝试:
export const withAuth = (Component: React.ComponentType) => (props) => {
const session = useSession()
if (session && session.data) {
return <Component {...props} />
}
return <LoginPage />
}
return AuthenticatedComponent
}
答案是 hidden in the docs。我必须在 _app.tsx
中指定以下 Auth
函数:
import { useEffect } from 'react'
import { AppProps } from 'next/app'
import { SessionProvider, signIn, useSession } from 'next-auth/react'
import { Provider } from 'urql'
import { client } from '@/client/graphql/client'
import '@/client/styles/index.css'
function Auth({ children }: { children: any }) {
const { data: session, status } = useSession()
const isUser = !!session?.user
useEffect(() => {
if (status === 'loading') return
if (!isUser) signIn()
}, [isUser, status])
if (isUser) {
return children
}
return <div>Loading...</div>
}
interface AppPropsWithAuth extends AppProps {
Component: AppProps['Component'] & { auth: boolean }
}
const CustomApp = ({ Component, pageProps: { session, ...pageProps } }: AppPropsWithAuth) => {
return (
<SessionProvider session={session}>
<Provider value={client}>
{Component.auth ? (
<Auth>
<Component {...pageProps} />
</Auth>
) : (
<Component {...pageProps} />
)}
</Provider>
</SessionProvider>
)
}
export default CustomApp
在我的实际页面上,我必须将 Component.auth
指定为 true
:
const Homepage = () => {
return (
<>
<div>Homepage</div>
</>
)
}
Homepage.auth = true
export default Homepage
上找到关于它的功能的一个很好的总结