You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 14登录后UI未自动更新,需手动刷新才恢复正常

Next.js 14登录后UI未自动更新,需手动刷新才恢复正常

我太懂你这种糟心的感觉了——登录完页面样式乱成一团、UI完全没跟上状态,非得手动刷一下才正常。在Next.js 14用Server Actions做认证的场景里,这种问题其实挺常见的,咱们一步步拆解问题、解决它:

先说说问题根源

从你贴的代码来看,主要有这几个可能的原因:

  • Server Action里多此一举的HTTP请求:你在服务端的登录Action里,又发起了一个到本地API的请求,这不仅绕了弯路,还可能导致请求上下文不一致,Cookie设置和页面跳转的时机没对齐。
  • Cookie设置的环境适配问题:你给Cookie加了secure: true,但在开发环境下localhost是HTTP协议,这会导致Cookie根本没被设置上,客户端自然识别不到登录状态,直到刷新后才可能读取到(或者根本读不到)。
  • 客户端组件的状态同步滞后:如果首页的导航栏这类组件依赖登录状态渲染,客户端初始Hydrate的时候可能还没拿到最新的Cookie,导致组件以未登录状态渲染,样式和布局全乱了。

具体解决方案

1. 把API逻辑直接整合到Server Action里

既然登录API和Server Action都是跑在服务端的,完全没必要分开调用,直接把数据库查询、JWT生成的逻辑移到Action里,既高效又能避免上下文问题:

"use server";
import { executeQuery } from "@/app/lib/db";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
import bcrypt from "bcryptjs";
import * as jose from "jose";

export default async function logInAction(
  currentState: any,
  formData: FormData
): Promise<string> {
  const email = formData.get("email");
  const password = formData.get("password");

  try {
    // 直接查询数据库,不用再调API
    const user = await executeQuery("SELECT * FROM user WHERE Email = ?", [email]);

    if (!user || user.length === 0) {
      return "Wrong email";
    }

    const isCorrectPassword = await bcrypt.compare(password as string, user[0].Password);

    if (!isCorrectPassword) {
      return "Wrong password!";
    }

    // 生成JWT
    const secret = new TextEncoder().encode(process.env.JWT_SECRET);
    const alg = "HS256";

    const jwt = await new jose.SignJWT({ UserID: user[0].UserID, Email: user[0].Email })
      .setProtectedHeader({ alg })
      .setExpirationTime("2h")
      .setSubject(user[0].UserID.toString())
      .sign(secret);

    // 注意:开发环境下不要用secure,否则Cookie设置失败
    cookies().set("Authorization", jwt, {
      secure: process.env.NODE_ENV === "production",
      httpOnly: true,
      expires: Date.now() + 24 * 60 * 60 * 1000 * 3,
      path: "/",
      sameSite: "strict",
    });

    // 跳转首页
    redirect("/homepage");
  } catch (error) {
    return "Server error";
  }
}

2. 确保客户端组件能及时获取登录状态

如果首页的导航栏是客户端组件,依赖Cookie判断登录状态,那要确保它能在页面加载时正确读取最新的Cookie:

"use client";
import { useEffect, useState } from "react";
import { cookies } from "next/headers";

const NavBar = () => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  useEffect(() => {
    const checkAuth = () => {
      const authCookie = cookies().get("Authorization");
      setIsLoggedIn(!!authCookie);
    };
    // 页面加载时检查一次
    checkAuth();
    // 如果需要实时监听Cookie变化,可以用第三方库(比如js-cookie)或者结合上下文状态管理
  }, []);

  // 剩下的渲染逻辑...
};

3. 检查样式加载方式

样式错乱大概率是Hydration不匹配导致的,建议把全局样式(比如Bootstrap、login-style.css)统一放到app/globals.css里导入,而不是在单个客户端组件里局部导入,这样能确保页面渲染时样式已经加载完成:

/* app/globals.css */
@import "bootstrap/dist/css/bootstrap.min.css";
@import "@/app/styles/login-style.css";

最后再验证一下

做完这些修改后,重新启动开发服务器,测试登录流程:

  • 登录后应该直接跳转到首页,样式正常显示
  • 导航栏等依赖登录状态的组件应该正确渲染
  • 不用手动刷新就能看到正确的UI

备注:内容来源于stack exchange,提问作者canerkaraca

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 09:48:03