登录页 mode 参数改为服务端直传,消除登录/注册表单切换闪烁

LoginPage 从 searchParams 提取 mode 作为 initialMode prop 传给 LoginClient,
替代客户端 useEffect 从 window.location.search 读取的方式,首次渲染即显示目标表单。

Tested: tsc --noEmit 通过, npm run build 通过
This commit is contained in:
2569718930@qq.com
2026-05-25 01:03:38 +08:00
parent 8957185062
commit 759ee7a8e4
2 changed files with 11 additions and 16 deletions
+8 -2
View File
@@ -2,7 +2,7 @@ import { LoginClient } from "@/components/auth/LoginClient";
import { I18nProvider } from "@/hooks/useI18n"; import { I18nProvider } from "@/hooks/useI18n";
type PageProps = { type PageProps = {
searchParams?: Promise<{ next?: string }>; searchParams?: Promise<{ next?: string; mode?: string }>;
}; };
function normalizeNextPath(input: string | undefined) { function normalizeNextPath(input: string | undefined) {
@@ -14,12 +14,18 @@ function normalizeNextPath(input: string | undefined) {
return raw; return raw;
} }
function normalizeMode(input: string | undefined): "login" | "signup" {
if (input === "signup") return "signup";
return "login";
}
export default async function LoginPage({ searchParams }: PageProps) { export default async function LoginPage({ searchParams }: PageProps) {
const params = (await searchParams) || {}; const params = (await searchParams) || {};
const nextPath = normalizeNextPath(params.next); const nextPath = normalizeNextPath(params.next);
const initialMode = normalizeMode(params.mode);
return ( return (
<I18nProvider> <I18nProvider>
<LoginClient nextPath={nextPath} /> <LoginClient nextPath={nextPath} initialMode={initialMode} />
</I18nProvider> </I18nProvider>
); );
} }
+3 -14
View File
@@ -26,12 +26,13 @@ type Mode = "login" | "signup";
type LoginClientProps = { type LoginClientProps = {
nextPath: string; nextPath: string;
initialMode?: Mode;
}; };
export function LoginClient({ nextPath }: LoginClientProps) { export function LoginClient({ nextPath, initialMode }: LoginClientProps) {
const router = useRouter(); const router = useRouter();
const { locale } = useI18n(); const { locale } = useI18n();
const [mode, setMode] = useState<Mode>("login"); const [mode, setMode] = useState<Mode>(initialMode ?? "login");
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -40,18 +41,6 @@ export function LoginClient({ nextPath }: LoginClientProps) {
const [resetSent, setResetSent] = useState(false); const [resetSent, setResetSent] = useState(false);
const [showPassword, setShowPassword] = useState(false); const [showPassword, setShowPassword] = useState(false);
useEffect(() => {
if (typeof window !== "undefined") {
const params = new URLSearchParams(window.location.search);
const m = params.get("mode");
if (m === "signup") {
setMode("signup");
} else if (m === "login") {
setMode("login");
}
}
}, []);
const supabaseReady = hasSupabasePublicEnv(); const supabaseReady = hasSupabasePublicEnv();
const isLogin = mode === "login"; const isLogin = mode === "login";
const siteOrigin = const siteOrigin =