我正在尝试使用 Next.js 创建一个具有身份验证和全局用户状态的 Web 应用程序。用户登录后,我想在导航栏中显示该用户,并与子组件共享该用户状态,这些子组件可能会进行需要用户信息的 API 调用。我使用 Next.js 13 以及
app
目录和 app/layout.js
文件来存储我的导航栏和用户状态。
我的问题是,从 JSON Web 令牌解码后,
app/layout.js
中的导航栏能够一致地显示用户名,但这不会显示在我的子组件 (app/loginsuccess/page.jsx
) 中,它也需要用户状态.
context/MyContext.js
import { createContext, useState } from "react";
const MyContext = createContext({
value: null,
setValue: () => {},
});
export const MyProvider = ({ children }) => {
const [value, setValue] = useState(null);
return (
<MyContext.Provider value={{ value, setValue }}>
{children}
</MyContext.Provider>
);
};
export default MyContext;
app/layout.jsx
"use client";
import "./globals.css";
import Link from "next/link";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import Cookies from "js-cookie";
import { MyProvider } from "@/context/MyContext";
const getUserFromJWTCookie = async () => {
const authToken = Cookies.get("token");
const response = await fetch("/api/session", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ token: authToken }),
});
const responseData = await response.json();
const username = responseData.username;
if (username) {
console.log("getUserFromJWTCookie", username);
return username;
}
};
export default function RootLayout({ children }) {
const router = useRouter();
const [user, setUser] = useState("");
useEffect(() => {
(async () => {
const user = await getUserFromJWTCookie();
setUser(user);
if (!user) {
router.replace("/logintest");
}
})();
}, [router]);
return (
<MyProvider value={{ value: user, setValue: setUser }}>
<html lang="en">
<body>
<nav className="bg-gray-800 text-white p-4">
<ul className="flex justify-center space-x-4">
<li className="hover:bg-gray-700 rounded-md p-2">
<Link href="/show">
<h1 className="text-xl font-semibold">Shows</h1>
</Link>
</li>
<li className="hover:bg-gray-700 rounded-md p-2">
<Link href="/user">
<h1 className="text-xl font-semibold">Users</h1>
</Link>
</li>
<li className="hover:bg-gray-700 rounded-md p-2">
<Link href="/loginsuccess">
<h1 className="text-xl font-semibold">{user}</h1>
</Link>
</li>
</ul>
</nav>
<main>{children}</main>
</body>
</html>
</MyProvider>
);
}
app/loginsuccess/page.jsx
"use client";
import { useContext, useState, useEffect } from "react";
import MyContext from "@/context/MyContext";
const ProtectedPage = () => {
const { value } = useContext(MyContext);
const [user, setUser] = useState("");
useEffect(() => {
setUser(value);
}, [value]);
return <div>Welcome! {user}</div>;
};
export default ProtectedPage;
非常感谢在我的子组件中同时进行此渲染的任何帮助:)
我认为问题可能出在你的
useEffect
中RootLayout
。我相信它说“仅在 router
更改时重新运行此 useEffect”...但是,虽然我不确定,但我不 think router
变量正在更改,因此 useEffect
不会不重新运行。
也许尝试将
authToken
作为 useEffect
的依赖项,这样当它更改时 user
就会从 getUserFromJWTCookie
重新生成:
const authToken = Cookies.get("token");
useEffect(() => {
(async () => {
const user = await getUserFromJWTCookie();
setUser(user);
if (!user) {
router.replace("/logintest");
}
})();
}, [router, authToken]);