reactjs 错误:“只允许在”使用服务器“文件中导出DMAC函数”

plupiseo  于 11个月前  发布在  React
关注(0)|答案(2)|浏览(162)

我试图使用layout.tsxapp目录下的Next.js 13有一个导航布局,是目前在所有的页面。我设法使它,当用户注销/登录,导航栏的变化,但问题是,我必须刷新页面(F5)看到导航栏上的变化。我认为这个问题是有关的该高速缓存,这就是为什么我尝试使用export const dynamic = 'force-dynamic'
我还将客户端组件添加到服务器组件,因为我认为这会是问题所在,但它并没有解决问题。我想使用export const dynamic = 'force-dynamic'来处理该高速缓存,但现在我遇到了一个似乎无法解决的错误。我得到的错误消息是:

错误

Only async functions are allowed to be exported in a "use server" file.

字符串
下面是详细的错误跟踪:

./app/components/ClientInsideServerLayout.tsx
Error: 
  x Only async functions are allowed to be exported in a "use server" file.
   ,-[C:\Users\zantl\OneDrive\Documentos\GitHub\sssss\gestion-gastos-supabase\app\components\ClientInsideServerLayout.tsx:2:1]
 2 | 
 3 | import { getSessionStatus } from "../ServerActions/isUserLoggedIn";
 4 | import ClientLayout from "./ClientLayout"
 5 | export const dynamic = 'force-dynamic'
   : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 6 | 
 7 | export async function ClientInsideServerLayout() {
 7 |     const isLoggedIn = await getSessionStatus();
   `----

代码

下面是导致错误的每个相关文件的代码:

文件:ClientInsideServerLayout.tsx

'use server';

import { getSessionStatus } from "../ServerActions/isUserLoggedIn";
import ClientLayout from "./ClientLayout"
export const dynamic = 'force-dynamic'

export async function ClientInsideServerLayout() {
    const isLoggedIn = await getSessionStatus();
    return (
      <>
      <ClientLayout isLoggedIn={isLoggedIn}></ClientLayout>
      </>
    )
  }

文件:ClientLayout.tsx

'use client'

import Link from 'next/link';
import { useRouter } from 'next/navigation'

export default function ClientLayout({ isLoggedIn }: { isLoggedIn: boolean }) {
  const router = useRouter();

  const signOut = async () => {
    try {
      const response = await fetch("http://localhost:3000/auth/sign-out", {
        method: "POST"
      });
  
      if (response.ok) {
        router.push("/")
        console.log('The resource has been permanently moved.');
      }     
    } catch (error: unknown) {
      console.error('An error occurred:', error);
    }
  };
  
  const logIn = () =>{
    router.push("/login")
  }
  
  
  
  
  return (
    <nav className="flex items-center justify-between flex-wrap bg-teal-500 p-6">
      <div className="flex items-center flex-shrink-0 text-white mr-6">
        {/* ... logo code ... */}
      </div>
      <div className="block lg:hidden">
        {/* ... button code ... */}
      </div>
      <div className="w-full block flex-grow lg:flex lg:items-center lg:w-auto">
        <div className="text-sm lg:flex-grow">
          <Link href="/ingresos" passHref>
            <span className="block mt-4 lg:inline-block lg:mt-0 text-teal-200 hover:text-white">
              Ingresos
            </span>
          </Link>
        </div>
        <div>
          {isLoggedIn ? (
            <button onClick={signOut} className="inline-block text-sm px-4 py-2 leading-none border rounded text-white border-white hover:border-transparent hover:text-teal-500 hover:bg-white lg:mt-0">Log Out</button>
          ) : (
            <>
              <button onClick={logIn} className="inline-block text-sm px-4 py-2 leading-none border rounded text-white border-white hover:border-transparent hover:text-teal-500 hover:bg-white lg:mt-0 mr-2">Log In</button>
              <button className="inline-block text-sm px-4 py-2 leading-none border rounded text-white border-white hover:border-transparent hover:text-teal-500 hover:bg-white lg:mt-0">Sign Up</button>
            </>
          )}
        </div>
      </div>
    </nav>
  );
}


下面是我使用的RootLayout的代码:

// Existing RootLayout code
'use server';
import './globals.css';
import { getSessionStatus } from './ServerActions/isUserLoggedIn';
import { ClientInsideServerLayout } from './components/ClientInsideServerLayout';

export default async function RootLayout({ children }: { children: React.ReactNode }) {
  const isLoggedIn = await getSessionStatus();

  return (
    <html lang="en">
      <body>
        <div>
          <ClientInsideServerLayout></ClientInsideServerLayout>
          {children}
        </div>
      </body>
    </html>
  );
}


下面是上下文的目录结构:

app/
  auth/
    callback/
      route.ts
    sign-in/
      route.ts
    sign-out/
      route.ts
    sign-up/
      route.ts
  components/
    ClientInsideServerLayout.tsx
    ClientLayout.tsx
    Login.tsx
    tablaIngresos.tsx
  ingresos/
    page.tsx
  login/
    messages.tsx
    page.tsx
  ServerActions/
    isUserLoggedIn.ts
  _examples/
    client-component/
      page.tsx
    route-handler/
      route.ts
    server-action/
      page.tsx
    server-component/
      page.tsx
  auth-form.tsx
  favicon.ico
  globals.css
  layout.tsx
  page.tsx
components/
  LogoutButton.tsx
  NextJsLogo.tsx
  SupabaseLogo.tsx
types/
  supabase.ts
.env.local
.gitignore
middleware.ts
next-env.d.ts
next.config.js
package-lock.json
package.json
postcss.config.js
README.md
tailwind.config.js
tsconfig.json

提问

有人能解释一下为什么会发生这个错误吗?我如何修复它,同时在单击注销按钮时保持布局更新功能?我想在不刷新页面的情况下实现这一点。
任何见解或建议将不胜感激!谢谢!

y53ybaqx

y53ybaqx1#

"use server"标签不能用于将组件在服务器端渲染为"use client"。它应该与Server Actions一起使用。如果您在文件的顶部添加"use server",则只能从中导出async函数:

'use server'

export async function addItem(data) { // ✅ This work
 // ...
}
export const foo = "bar"; // ❌ This won't work

字符串
顶部没有"use client"的组件是服务器组件,因此从ClientInsideServerLayout.tsxRootLayout.tsx中删除'use server'
现在,您必须手动刷新页面以反映注销状态的事实可以在router.refresh()的帮助下处理:

const signOut = async () => {
  try {
    const response = await fetch("http://localhost:3000/auth/sign-out", {
      method: "POST",
    });

    if (response.ok) {
      router.push("/");
      router.refresh();
    }
  } catch (error: unknown) {
    console.error("An error occurred:", error);
  }
};


有关为什么使用router.refresh()的更多信息,请查看来自Next.js的Tim Neutkens的article

yebdmbv4

yebdmbv42#

我在接下来的14中遇到了一个类似的问题,我使用index.ts文件来集中服务器操作的导出。问题是我需要从index.ts文件本身删除'use server'
错误:

'use server'

/**
 * Simplify and centralize server action exports
 */
export { signIn } from "./signIn";
export { signOut } from "./signOut";
export { createComment } from "./createComment";
export { createPost } from "./createPost";
export { createTopic } from "./createTopic";

字符串
正确:从文件顶部删除使用服务器。

/**
 * Simplify and centralize server action exports
 */
export { signIn } from "./signIn";
export { signOut } from "./signOut";
export { createComment } from "./createComment";
export { createPost } from "./createPost";
export { createTopic } from "./createTopic";


评论服务器操作示例

"use server";

export async function createComment() {}


正确地从它导出一个async函数,在每个服务器操作文件的顶部使用use server
希望这对某人有帮助。

相关问题