reactjs 下一个身份验证useSession在第一次呈现时未获取会话

kknvjkwl  于 2023-06-05  发布在  React
关注(0)|答案(2)|浏览(186)

我正在尝试使用NextJS v13和Next Auth v4构建一个网站。每当加载页面/组件时,使用useSession钩子时,会话不会在第一次呈现时返回,因此,许多组件无法正常工作。
例如,下面的代码应该为经过身份验证的用户加载问题:

'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>
  )
}

这是我的ProviderWrapper组件,它 Package 了主应用程序:

'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>
  )
}

下面是layout.tsx文件:

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>
  )
}

有人知道为什么next-auth会这样吗?

4uqofj5v

4uqofj5v1#

初始加载会话将是未定义的,因为它没有传递给提供程序。尝试将***现有会话***传递给提供程序,如下所示。

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,
  };
};
jjhzyzn0

jjhzyzn02#

经过一些研究和@Thusithz的回答,我发现this guide可以使用Next Auth和TypeScript实现正确的身份验证。所以我把代码改成了下面的代码,它工作了。
我将/src/components/PriverWrapper.tsx重命名为src/context/AuthProvider.tsx,并将代码更改为以下内容:

'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>
}

然后将其应用于/src/app/layout.tsx文件,用AuthProvider Package 节点并传递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>
  )
}

所以,这是预期的。

相关问题