在Next.js中使用服务器操作设置cookie 13.4

ecfsfe2w  于 2023-11-18  发布在  其他
关注(0)|答案(1)|浏览(166)

在服务器操作中设置Cookie的工作方式

我已经阅读了来自(hlasensky和AnasSafi)[https://stackoverflow.com/questions/76483495/cant-set-cookie-in-server-action-next-js-13-4]的问题和答案,但我必须说,他们是如何做的,甚至是做了什么,都不太清楚(缺乏代码问题和解决方案的例子)
所以,我的问题是。
我有这个服务器动作,它应该创建一个cookie并存储用户首选语言。

'use server';

import { Locale } from "@/lib/translations/i18n.config";
import { cookies } from 'next/headers';

export default async function setLocaleCookie(locale: Locale) {
    cookies().set({
        name: 'NEXT_LOCALE',
        value: locale,
        path: '/',
        maxAge: 60 * 60 * 24 * 30, // 30 days
    })
    console.log("NEXT_LOCALE cookie set to:", locale)
}

字符串
接下来,我需要在用户选择其首选语言时调用此函数。
所以,我做了一个组件(最好是客户端,但如果需要,可以转换为服务器)。

(/components/LocaleSwitcher.tsx)

'use client';

import { i18nConfig, Locale } from '@/lib/translations/i18n.config';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { Button } from '../ui/button';
import setLocaleCookie from '@/lib/server_actions/cookies/locale';

export default function LocaleSwitcher() {
  
  const pathName = usePathname()
  function redirectedPathName(locale: Locale) {
    if (!pathName) return '/'
    const segments = pathName.split('/')
    segments[1] = locale
    return segments.join('/')
  }

  const locales = i18nConfig.locales
  return (
    <ul className='flex gap-x-3'>
      {locales.map(locale => {
        return (
          <li key={locale}>
            <Link
              href={redirectedPathName(locale)}
              className='rounded-md border bg-black px-3 py-2 text-white'
              locale={locale}
            >
              {locale}
            </Link>
            <form action={setLocaleCookie(locale)}>

              <Button
                type="submit"
                className='rounded-md border'
              >
                {locale}
              </Button>
            </form>
          </li>
        )
      })}
    </ul>
  )
}


此组件位于Header服务器组件内部

(/components/Header.tsx)

/** @format */

import { User, getServerSession } from 'next-auth';
import Logo from './Logo';
import NavigationWeb from './NavigationWeb';
import UserMenu from './UserMenu';
import LocaleSwitcher from './LocaleSwitcher';
import { authOptions } from '@/lib/helpers/authOptions';
import { Locale } from '@/lib/translations/i18n.config';

interface NavbarProps {
  user?: User;
  locale?: Locale;
}

export default async function Header({ user, locale }: NavbarProps) {
  const session = await getServerSession(authOptions);
  user = session?.user;

  return (
    <div className="z-10 border-b py-4 px-16 w-full">
      <div className="flex flex-row items-center justify-between gap-3 md:gap-0">
        <Logo />
        <div className="flex justify-between items-center gap-4">
          <NavigationWeb />
          <UserMenu user={user} />
          <LocaleSwitcher /> // HERE IS THE LOCALE SWITCHER COMPONENT
        </div>
      </div>
    </div>
  );
}


它本身嵌套在RootLayout**(app/[locale]/layout.ts)**中:

/** @format */

import { Nunito, Inter } from 'next/font/google';
import './globals.css';
import Header from '@/components/header/Header';
import NextAuthSessionProvider from '@/components/providers/SessionProvider';
import { ThemeProvider } from '@/components/providers/ThemeProvider';
import Footer from '@/components/footer/Footer';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/helpers/authOptions';
import localFont from 'next/font/local';
import { Toaster } from '@/components/ui/toaster';
import { i18nConfig, Locale } from '@/lib/translations/i18n.config';

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
});

const nunito = Nunito({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-nunito',
});

const gambettaReg = localFont({
  src: './fonts/Gambetta-Regular.woff2',
  display: 'swap',
  variable: '--font-gambetta-reg',
});

const gambettaSemi = localFont({
  src: './fonts/Gambetta-Semibold.woff2',
  display: 'swap',
  variable: '--font-gambetta-semi',
});

const circularBold = localFont({
  src: './fonts/CircularXXWeb-Bold.woff2',
  display: 'swap',
  variable: '--font-circular-bold',
});

export const metadata = {
  title: 'App Template',
  description: 'A template for Next.js applications',
};

export async function generateStaticParams() {
  return i18nConfig.locales.map(locale => ({ locale: locale }))
}

export default async function RootLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: { locale: Locale };
  }) {

  const session = await getServerSession(authOptions);

  return (
    <NextAuthSessionProvider session={session}>
      <html lang={params.locale}>
        <body
          className={`${circularBold.variable} ${gambettaReg.variable} ${gambettaSemi.variable} ${nunito.variable} ${inter.variable} font-inter`}
        >
          <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
            <main className="flex flex-col justify-between items-center min-h-screen min-w-screen">
              <Header
                user={session?.user}
                locale={params.locale}
              />
              {children}
              <Footer
              // locale={params.locale}
              />
              <Toaster
              // locale={params.locale}
              />
            </main>
          </ThemeProvider>
        </body>
      </html>
    </NextAuthSessionProvider>
  );
}


我以为我在Next.js文档方面做得很好。但我总是收到这个错误日志:

Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.
    at AppContainer (C:\Users\samue\repos\app-template\node_modules\next\dist\server\render.js:341:29)
    at AppContainerWithIsomorphicFiberStructure (C:\Users\samue\repos\app-template\node_modules\next\dist\server\render.js:377:57)
    at div
    at Body (C:\Users\samue\repos\app-template\node_modules\next\dist\server\render.js:677:21)
Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.
    at AppContainer (C:\Users\samue\repos\app-template\node_modules\next\dist\server\render.js:341:29)
    at AppContainerWithIsomorphicFiberStructure (C:\Users\samue\repos\app-template\node_modules\next\dist\server\render.js:377:57)
    at div
    at Body (C:\Users\samue\repos\app-template\node_modules\next\dist\server\render.js:677:21)
Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.
    at PathnameContextProviderAdapter (C:\Users\samue\repos\app-template\node_modules\next\dist\shared\lib\router\adapters.js:78:11)
    at AppContainer (C:\Users\samue\repos\app-template\node_modules\next\dist\server\render.js:341:29)
    at AppContainerWithIsomorphicFiberStructure (C:\Users\samue\repos\app-template\node_modules\next\dist\server\render.js:377:57)
    at div
    at Body (C:\Users\samue\repos\app-template\node_modules\next\dist\server\render.js:677:21)
Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.
    at PathnameContextProviderAdapter (C:\Users\samue\repos\app-template\node_modules\next\dist\shared\lib\router\adapters.js:78:11)
    at AppContainer (C:\Users\samue\repos\app-template\node_modules\next\dist\server\render.js:341:29)
    at AppContainerWithIsomorphicFiberStructure (C:\Users\samue\repos\app-template\node_modules\next\dist\server\render.js:377:57)
    at div
    at Body (C:\Users\samue\repos\app-template\node_modules\next\dist\server\render.js:677:21)

所以我已经尝试了不同的方法.但任何最好的东西给我一个“饼干只能在服务器操作或路由器修改”.但我使用的是服务器操作!

我已经检查了Next.js issue 51875上的讨论,但我看不出这对我有什么帮助?
我做错了什么?

idfiyjo8

idfiyjo81#

TLDR:你必须在客户端组件中调用你的服务器操作。注意:这些代码片段不会在客户端组件中运行。

'use server'
 
import { cookies } from 'next/headers'
 
export async function create() {
  cookies().set("name", "test");
}

字符串

"use client"

...

useEffect(() => {
    setMounted(true);
    create();
  }, []);

相关问题