英文:
Next Auth useSession does not get session at first render
问题
I am trying to build a website using NextJS v13 and Next Auth v4. Whenever a page/component is loaded, the session is not returned in the first render when using useSession
hook and because of this, many components don't work like they should...
For instance, the following code should load the questions for authenticated users:
'use client'
import { useEffect, useState } from 'react'
import { Question } from '@prisma/client'
import { useSession } from 'next-auth/react'
function QuestionPage() {
const { data: session } = useSession() // this is null
const [questions, setQuestions] = useState<Question[]>([])
const [questionStatus, setQuestionStatus] = useState('');
useEffect(() => {
console.log('Session: ', session)
if (!session) return;
setQuestionStatus('Loading questions...');
fetch('/api/questions')
.then((res) => res.json())
.then((data) => {
setQuestions(data.questions)
setQuestionStatus('');
})
}, [])
return (
<div>
<p>{questionStatus}</p>
{questions && questions.map(question => {
<p key={question.id}>{question.title}</p>
})}
</div>
)
}
This is my ProviderWrapper
component that wraps the main app:
'use client'
import QuestionContextWrapper from '@/context/QuestionContext'
import { SessionProvider } from 'next-auth/react'
export const metadata = {
title: 'My App',
description: 'My description',
}
export default function ProvidersWrapper({ children }: { children: React.ReactNode }) {
return (
<SessionProvider>
<QuestionContextWrapper>
{children}
</QuestionContextWrapper>
</SessionProvider>
)
}
And this is the layout.tsx
file:
import './globals.css'
import Header from '@/components/Header'
import ProvidersWrapper from './ProvidersWrapper'
import Footer from '@/components/Footer'
export const metadata = {
title: 'My app',
description: 'My description',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<ProvidersWrapper>
<Header />
{children}
<Footer />
</ProvidersWrapper>
</body>
</html>
)
}
Anyone knows why is next-auth
behaving like this?
英文:
I am trying to build a website using NextJS v13 and Next Auth v4. Whenever a page/component is loaded, the session is not returned in the first render when using useSession
hook and because of this, many components don't work like they should...
For instance, the following code should load the questions for authenticated users:
'use client'
import { useEffect, useState } from 'react'
import { Question } from '@prisma/client'
import { useSession } from 'next-auth/react'
function QuestionPage() {
const { data: session } = useSession() // this is null
const [questions, setQuestions] = useState<Question[]>([])
const [questionStatus, setQuestionStatus] = useState('');
useEffect(() => {
console.log('Session: ', session)
if (!session) return;
setQuestionStatus('Loading questions...');
fetch('/api/questions')
.then((res) => res.json())
.then((data) => {
setQuestions(data.questions)
setQuestionStatus('');
})
}, [])
return (
<div>
<p>{questionStatus}</p>
{questions && questions.map(question => {
<p key={question.id}>{question.title}</p>
})}
</div>
)
}
This is my ProviderWrapper
component that wraps the main app:
'use client'
import QuestionContextWrapper from '@/context/QuestionContext'
import { SessionProvider } from 'next-auth/react'
export const metadata = {
title: 'My App',
description: 'My description',
}
export default function ProvidersWrapper({ children }: { children: React.ReactNode }) {
return (
<SessionProvider>
<QuestionContextWrapper>
{children}
</QuestionContextWrapper>
</SessionProvider>
)
}
And this is the layout.tsx
file:
import './globals.css'
import Header from '@/components/Header'
import ProvidersWrapper from './ProvidersWrapper'
import Footer from '@/components/Footer'
export const metadata = {
title: 'My app',
description: 'My description',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<ProvidersWrapper>
<Header />
{children}
<Footer />
</ProvidersWrapper>
</body>
</html>
)
}
Anyone knows why is next-auth
behaving like this?
答案1
得分: 2
经过一些研究,根据 @Thusithz 的回答,我找到了这个指南,以使用 Next Auth 和 TypeScript 实现正确的身份验证。因此,我将我的代码更改为以下内容,并且它运行正常。
我将 /src/components/PriverWrapper.tsx
重命名为 src/context/AuthProvider.tsx
,并且也更改了代码如下:
'使用客户端'
import { Session } from 'next-auth'
import { SessionProvider } from 'next-auth/react'
export const metadata = {
title: 'My App',
description: 'My description',
}
export interface AuthContextProps {
children: React.ReactNode
session: Session
}
export default function AuthContext({ children }: AuthContextProps) {
return <SessionProvider>{children}</SessionProvider>
}
然后将其应用于 /src/app/layout.tsx
文件,使用 AuthProvider
包装节点并传递 session
变量:
import './globals.css'
import Header from '@/components/Header'
import AuthProvider from '@/context/AuthContext'
import Footer from '@/components/Footer'
import { Session } from 'next-auth'
async function getSession(cookie: string): Promise<Session> {
const response = await fetch(`${process.env.NEXTAUTH_URL}/session`, {
headers: {
cookie,
}
})
const session = await response.json()
return Object.keys(session).length > 0 ? session : null
}
export const metadata = {
title: 'My app',
description: 'My description',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
const session = await getSession(headers().get('cookie') ?? '');
return (
<html lang="en">
<body>
<AuthContext session={session}>
<Header />
{children}
<Footer />
</AuthContext>
</body>
</html>
)
}
因此,这按预期工作。
英文:
After some research and due to the @Thusithz's answer, I have found this guide to implement proper authentication using Next Auth and TypeScript. So I changed my code to the following and it worked.
I have renamed /src/components/PriverWrapper.tsx
to src/context/AuthProvider.tsx
and changed the code as well to the following:
'use client'
import { Session } from 'next-auth'
import { SessionProvider } from 'next-auth/react'
export const metadata = {
title: 'My App',
description: 'My description',
}
export interface AuthContextProps {
children: React.ReactNode
session: Session
}
export default function AuthContext({ children }: AuthContextProps) {
return <SessionProvider>{children}</SessionProvider>
}
And then applied this to the /src/app/layout.tsx
file wrapping the node with AuthProvider
and passing the session
variable:
import './globals.css'
import Header from '@/components/Header'
import AuthProvider from '@/context/AuthContext'
import Footer from '@/components/Footer'
import { Session } from 'next-auth'
async function getSession(cookie: string): Promise<Session> {
const response = await fetch(`${process.env.NEXTAUTH_URL}/session`, {
headers: {
cookie,
}
})
const session = await response.json()
return Object.keys(session).length > 0 ? session : null
}
export const metadata = {
title: 'My app',
description: 'My description',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
const session = await getSession(headers().get('cookie') ?? '');
return (
<html lang="en">
<body>
<AuthContext session={session}>
<Header />
{children}
<Footer />
</AuthContext >
</body>
</html>
)
}
So, this works as expeted.
答案2
得分: 1
初始加载会话将未定义,因为它未传递给提供程序。尝试像下面这样将现有会话传递给提供程序。
export default function ProvidersWrapper({ children, session }: { children: React.ReactNode }) {
return (
<SessionProvider baseUrl={/* BASE_URL */} refetchInterval={60 * 5} session={session}>
<QuestionContextWrapper>{children}</QuestionContextWrapper>
</SessionProvider>
);
}
ProvidersWrapper.getInitialProps = async (context) => {
const { ctx } = context;
const session = await getSession(ctx);
return {
session,
};
};
英文:
Initial load session will be undefined since it's not pass to provider. Try to pass existing session to provider like below.
export default function ProvidersWrapper({ children, session }: { children: React.ReactNode }) {
return (
<SessionProvider baseUrl={/* BASE_URL */} refetchInterval={60 * 5} session={session}>
<QuestionContextWrapper>{children}</QuestionContextWrapper>
</SessionProvider>
);
}
ProvidersWrapper.getInitialProps = async (context) => {
const { ctx } = context;
const session = await getSession(ctx);
return {
session,
};
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论