我想根据验证和身份验证是否成功从服务器操作获取消息。
登录方法被正确调用,我试了一下。问题是消息永远不会显示在表单所在的组件文件中,它永远不会发送到 LoginForm 或保存在状态中。
actions.js:
"use server";
export async function login(previousState, formData) {
return {
message: "Please enter a valid email",
};
}
它使用useFormState。我看到有新的 useActionState,但它还没有,或者不在我的项目版本中。 Next.js 官方文档使用了 useFormState,但是 URL 指向了 React 的 useActionState。
"use client";
import { useFormStatus, useFormState } from "react-dom";
const LoginForm = () => {
const initialState = {
message: "",
};
const [state, formAction] = useFormState(login, initialState); // error message never saves in state or shows on screen
useEffect(() => {
console.log("change:" + state);
}, [state]); // never changes so it is never triggered, except on load
return (
<form
action={formAction}
>
<div>
<label htmlFor="email">Email:</label>
<input
id="email"
name="email"
type="email"
required
/>
</div>
<div>
<SubmitButton />
<span>
{JSON.stringify(state)} // always {"message":""}
{state.message} // empty/""
</span>
<p aria-live="polite" className="sr-only">
{state?.message} // empty/""
</p>
</div>
</form>
);
};
const SubmitButton = () => {
const { pending } = useFormStatus(); // works well
return (
<button formAction={login} disabled={pending}>
{pending ? "Checking..." : " Log in"}
</button>
);
};
另一方面,具有挂起状态的 useFormStatus 效果很好。
我不确定问题是否出在我的中间件中,因为我正在使用 Supabase。
import { updateSession } from "./utils/supabase/middleware";
export async function middleware(request) {
console.log("middleware " + JSON.stringify(request));
return await updateSession(request);
}
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
* Feel free to modify this pattern to include more paths.
*/
"/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
],
};
import { createServerClient } from "@supabase/ssr";
import { NextResponse } from "next/server";
export async function updateSession(request) {
let supabaseResponse = NextResponse.next({
request,
});
console.log("sesija " + JSON.stringify(request));
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
{
cookies: {
getAll() {
return request.cookies.getAll();
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
request.cookies.set(name, value)
);
supabaseResponse = NextResponse.next({
request,
});
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
);
},
},
}
);
// IMPORTANT: Avoid writing any logic between createServerClient and
// supabase.auth.getUser(). A simple mistake could make it very hard to debug
// issues with users being randomly logged out.
const {
data: { user },
} = await supabase.auth.getUser();
const unallowedPaths = ["/builder"];
console.log(request.nextUrl.pathname);
if (
!user &&
unallowedPaths.some((path) => request.nextUrl.pathname.startsWith(path))
) {
console.log("nema usera i redirecta middleware");
// no user, potentially respond by redirecting the user to the login page
const url = request.nextUrl.clone();
url.pathname = "/login";
return NextResponse.redirect(url);
}
// IMPORTANT: You *must* return the supabaseResponse object as it is. If you're
// creating a new response object with NextResponse.next() make sure to:
// 1. Pass the request in it, like so:
// const myNewResponse = NextResponse.next({ request })
// 2. Copy over the cookies, like so:
// myNewResponse.cookies.setAll(supabaseResponse.cookies.getAll())
// 3. Change the myNewResponse object to fit your needs, but avoid changing
// the cookies!
// 4. Finally:
// return myNewResponse
// If this is not done, you may be causing the browser and server to go out
// of sync and terminate the user's session prematurely!
return supabaseResponse;
}
这是我的服务器控制台:
middleware {"sourcePage":"/middleware"}
sesija {"sourcePage":"/middleware"}
Please enter a valid email
POST /login 200 in 28ms
由于您已经在 Form 标签中使用了 formAction,因此无需在 SubmitButton 中再次使用它。试试这个:
const SubmitButton = () => {
const { pending } = useFormStatus(); // works well
return (
<button type="submit" disabled={pending}>
{pending ? "Checking..." : " Log in"}
</button>
);
};