客户端组件未接收服务器操作响应 Next.js 14

问题描述 投票:0回答:1

我正在尝试在 Next.js 中进行错误处理。我正在使用传递到表单并在提交表单时调用的服务器操作,如下所示::

表单组件

"use client";
import PasswordInput from "@components/PasswordInput";
import ProvidersLogin from "@components/ProvidersLogin";
import { Button, Divider, Input, Link } from "@nextui-org/react";
import loginCredentials from "@utils/loginCredentials";
import ErrorToast from "@components/ErrorToast";
import { useFormState } from "react-dom";
import { useEffect } from "react";

const initialState = {
  message: "",
};

export default function Login() {
  const [error, formAction, isPending] = useFormState(
    loginCredentials,
    initialState
  );

  useEffect(() => {
    console.log("error", error);
  }, [error]);

  return (
      <div className="flex flex-col gap-4 items-center justify-center w-full h-full min-h-screen">
        <form action={formAction} className="flex flex-col gap-4 min-w-96">
          <h1 className="font-black text-4xl">Login</h1>
          <p className="text-default-500 text-lg">
            Let{"'"}s make it even better
          </p>
          <ProvidersLogin />
          {/* Commented till error handling is fixed, as currently it does nothing */}
          <Divider />
          <Input
            type="email"
            name="email"
            label="Email"
            labelPlacement="outside"
            placeholder="Enter your email"
            size="lg"
            // biome-ignore lint/a11y/noPositiveTabindex: <explanation>
            tabIndex={1}
            required
            isDisabled={isPending}
            // description=""
          />
          <div className="relative flex flex-col w-full">
            <Link
              className="absolute -top-1 tap-highlight-transparent outline-none text-medium text-primary no-underline hover:opacity-80 active:opacity-disabled transition-opacity self-end"
              href="/forgotpassword"
            >
              Forgot Password?
            </Link>
            <PasswordInput
              name="password"
              label="Password"
              placeholder="Enter your password"
              required
              // biome-ignore lint/a11y/noPositiveTabindex: <explanation>
              tabIndex={2}
              isDisabled={isPending}
            />
          </div>
          <div className="flex flex-row gap-1.5 justify-center items-center w-full -mt-2 -mb-1">
            Don{"'"}t have an account?
            <Link href="/signup">Sign Up</Link>
          </div>
          <p>{error?.message}</p>
          <div className="flex flex-row gap-4 items-center justify-between">
            <Button
              as={Link}
              href="/"
              color="danger"
              variant="light"
              isDisabled={isPending}
            >
              Cancel
            </Button>
            <Button type="submit" color="primary" isLoading={isPending}>
              Login
            </Button>
          </div>
        </form>
      </div>
  );
}

服务器操作

"use server";
import { signIn } from "@auth";
import { redirect, RedirectType } from "next/navigation";

export default async function loginCredentials(
  prevState: { message: string },
  data: FormData
) {
  try {
    const email = data.get("email")?.toString();
    const password = data.get("password")?.toString();

    if (!email || !password) {
      throw new Error("Please fill in all fields");
    }

    await signIn("credentials", {
      email,
      password,
      redirect: false,
      // callbackUrl: "/dashboard",
    });
  } catch (error) {
    // @ts-ignore
    return { message: error.cause.err.message };
  }
  redirect("/dashboard", RedirectType.replace);
}

注意:我知道我正在使用

error.cause.err.message
,如next-auth 5,当凭据提供程序授权函数中的CredentialsSignIn错误引发错误时(如果在服务器端调用signIn函数) ,来自 CredentialsSignIn 的消息存储在
error.cause.err.message
中。

问题是当我尝试实现此操作时,服务器操作没有返回响应对象,即

state
仍然存在
undefined

我什至尝试在没有

useFormState
的情况下实现此功能: 表单组件

"use client";
import PasswordInput from "@components/PasswordInput";
import ProvidersLogin from "@components/ProvidersLogin";
import { Button, Divider, Input, Link } from "@nextui-org/react";
import loginCredentials from "@utils/loginCredentials";
import ErrorToast from "@components/ErrorToast";
import { useFormState } from "react-dom";
import { useEffect } from "react";

const initialState = {
  message: "",
};

export default function Login() {
  const [error, setError] = useState<string>()
  const [isPending, setIsPending] = useState(false)

  useEffect(() => {
    console.log("error", error);
  }, [error]);

  return (
      <div className="flex flex-col gap-4 items-center justify-center w-full h-full min-h-screen">
        <form action={async (data) => {
          setIsPending(true)
          const res = await loginCredentials({message: ""}, data)
          if (res?.message) {
            setError(res.message)
          }
        }} className="flex flex-col gap-4 min-w-96">
          <h1 className="font-black text-4xl">Login</h1>
          <p className="text-default-500 text-lg">
            Let{"'"}s make it even better
          </p>
          <ProvidersLogin />
          {/* Commented till error handling is fixed, as currently it does nothing */}
          <Divider />
          <Input
            type="email"
            name="email"
            label="Email"
            labelPlacement="outside"
            placeholder="Enter your email"
            size="lg"
            // biome-ignore lint/a11y/noPositiveTabindex: <explanation>
            tabIndex={1}
            required
            isDisabled={isPending}
            // description=""
          />
          <div className="relative flex flex-col w-full">
            <Link
              className="absolute -top-1 tap-highlight-transparent outline-none text-medium text-primary no-underline hover:opacity-80 active:opacity-disabled transition-opacity self-end"
              href="/forgotpassword"
            >
              Forgot Password?
            </Link>
            <PasswordInput
              name="password"
              label="Password"
              placeholder="Enter your password"
              required
              // biome-ignore lint/a11y/noPositiveTabindex: <explanation>
              tabIndex={2}
              isDisabled={isPending}
            />
          </div>
          <div className="flex flex-row gap-1.5 justify-center items-center w-full -mt-2 -mb-1">
            Don{"'"}t have an account?
            <Link href="/signup">Sign Up</Link>
          </div>
          <p>{error}</p>
          <div className="flex flex-row gap-4 items-center justify-between">
            <Button
              as={Link}
              href="/"
              color="danger"
              variant="light"
              isDisabled={isPending}
            >
              Cancel
            </Button>
            <Button type="submit" color="primary" isLoading={isPending}>
              Login
            </Button>
          </div>
        </form>
      </div>
  );
}

但是服务器操作返回

undefined
,我还检查了服务器操作实际上被调用并且它被调用了。

请有人提供解决方案

注意:我知道

useFormState
将被
useActionState
取代,我尝试了一下,它仍然返回
undefined

reactjs next.js error-handling nextjs14 server-action
1个回答
0
投票

我终于明白了。

问题是,一旦我停止将标题传递给

middleware
,我就试图修改
NextResponse.next()
中的标题,问题已解决。

© www.soinside.com 2019 - 2024. All rights reserved.