Next.js 13 使用layout.js 的全局上下文

问题描述 投票:0回答:1

我正在尝试使用 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;

非常感谢在我的子组件中同时进行此渲染的任何帮助:)

javascript reactjs next.js state react-context
1个回答
0
投票

我认为问题可能出在你的

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]);
© www.soinside.com 2019 - 2024. All rights reserved.