Next.js设置Cookie报useContext空值读取错误如何解决
问题根因
触发报错的核心原因是违反React Hooks调用规则+运行环境混用,和React版本、多副本问题无关:
[...nextauth].js是Next.js服务端API路由,代码运行在Node.js服务端,不存在React组件渲染上下文- 普通工具函数
AuthReducer不属于React函数组件/自定义Hook,却在内部调用了useCookies这个React Hook,还将该函数放到服务端的NextAuth回调中执行,完全不符合Hooks的调用要求 - 错误混用客户端Cookie Hook和服务端逻辑:
react-cookie提供的Hook仅能在客户端组件环境运行,根本无法在NextAuth的服务端回调中执行
正确实现方案
不需要额外编写reducer手动调用Cookie库,NextAuth本身原生支持自定义Cookie配置,也支持持久化存储后端返回的自定义业务token,根据需求选对应方案即可。
方案1:使用NextAuth原生配置自定义Cookie(推荐)
直接在NextAuth初始化配置中添加cookies字段,即可全局修改NextAuth下发所有Cookie的属性,同时可以通过回调把后端返回的业务token存在NextAuth内置的JWT/Session中,不需要单独维护额外Cookie:
// pages/api/auth/[...nextauth].js import NextAuth from "next-auth"; import GoogleProvider from "next-auth/providers/google"; import axios from "axios"; export default NextAuth({ providers: [ GoogleProvider({ clientId: process.env.cid, clientSecret: process.env.sid, }), ], // 自定义NextAuth内置Cookie规则 cookies: { sessionToken: { name: "next-auth.session-token", options: { httpOnly: true, sameSite: "lax", path: "/", secure: process.env.NODE_ENV === "production", maxAge: 3600 * 24, // 自定义1天过期时间 } }, // csrfToken、callbackUrl等其他内置Cookie也可在此处修改配置 }, callbacks: { // 首次登录时拉取后端业务token,存入JWT async jwt({ token, account }) { if (account?.provider === "google") { const apiRes = await axios.post("http://localhost:5000/user/googlelogin", { // 仅传必要字段,不要明文传输完整用户敏感信息 providerAccountId: account.providerAccountId, email: account.email, name: account.name, }); token.customBusinessToken = apiRes.data.token; } return token; }, // 将JWT中的自定义字段透传给客户端可访问的session async session({ session, token }) { session.userToken = token.customBusinessToken; return session; }, async signIn({ profile, account }) { if (account.provider === "google") { return !!profile.email_verified; } return true; } }, });
方案2:服务端回调中下发额外自定义Cookie
如果确实需要下发完全独立的自定义业务Cookie,不要使用react-cookie的Hook,直接在NextAuth处理函数中拿到请求/响应对象,用服务端兼容的Cookie工具操作即可:
- 先删除原有写了Hook逻辑的
auth.js文件,该文件完全不符合Hook调用规则,无保留价值 - 重写NextAuth路由处理逻辑:
// pages/api/auth/[...nextauth].js import NextAuth from "next-auth"; import GoogleProvider from "next-auth/providers/google"; import axios from "axios"; import { setCookie } from 'cookies-next'; // 导出带req/res上下文的处理函数 export default async function authHandler(req, res) { return NextAuth(req, res, { providers: [ GoogleProvider({ clientId: process.env.cid, clientSecret: process.env.sid, }), ], callbacks: { async signIn({ account, profile }) { if (account.provider === "google") { const apiRes = await axios.post("http://localhost:5000/user/googlelogin", { object: profile, }); // 服务端环境直接调用setCookie,传入req/res即可,不需要Hook setCookie("user", JSON.stringify(apiRes.data.token), { req, res, path: "/", maxAge: 3600 * 24, sameSite: "lax", httpOnly: true, // 存储token的敏感Cookie建议开启httpOnly,降低XSS窃取风险 }); return !!profile.email_verified; } return true; }, }, }) }
注意:
useCookies这类React Hook 仅允许在React函数组件、自定义Hook的顶层作用域调用,禁止在普通工具函数、服务端代码、条件分支、循环逻辑中调用,否则必然触发Hook规则报错。
内容的提问来源于stack exchange,提问作者NRA 1
相关产品推荐
相关产品推荐

