React 上下文:开发者工具中的 SessionStorage 数据出现但在导航栏中显示为空白

React Context: Sessionstorage data in developer tools appears but appears blank in navbar

我正在使用 React Context 将数据存储到 sessionstorage 中以用于登录和注销。我保存了三样东西:用于保存用户 ID 的 IDContext、用于保存用户用户名的 UserNameContext 以及用于简单查看登录用户是否为管理员的 AdminContext。我想在导航栏上显示登录用户的用户名,例如 (Welcome, {user}) 但它只显示为 (Welcome, {})。我通过开发者工具检查了sessionstorage,它显示

username:""user""

那么为什么它在导航栏上显示为空白,我没有正确抓取数据吗?

auth.js:

import { createContext, useContext } from "react";

export const UserNameContext = createContext();
export const IDContext = createContext();
export const AdminContext = createContext();

export function useUserName() {
  return useContext(UserNameContext);
}

export function useID() {
  return useContext(IDContext);
}

export function useAdmin() {
  return useContext(AdminContext);
}

navbar.js:

import React from "react";
import { Navbar, Nav, Container } from "react-bootstrap";
import { Link } from "react-router-dom";
import { useID, useUserName, useAdmin } from "../context/auth";

function Navigation(props) {
    const { IDTokens } = useID();
    const { usernameTokens } = useUserName();
    const { adminTokens } = useAdmin();

    function adminNav() {
        return (
            <Navbar.Collapse id="basic-navbar-nav">
                <Nav className="me-auto">
                    <Link to="#">Placeholder</Link>
                </Nav>
                <Nav>
                    <Link to={`/${usernameTokens}`}>Welcome, {usernameTokens}</Link>
                    <Link to="/logout">Log Out</Link>
                </Nav>
            </Navbar.Collapse>
        )
    }

    function loggedInNav() {
        return (
            <Navbar.Collapse id="basic-navbar-nav">
                <Nav className="me-auto">
                    <Link to="#">Placeholder</Link>
                </Nav>
                <Nav>
                    <Link to={`/${usernameTokens}`}>Welcome, {usernameTokens}</Link>
                    <Link to="/logout">Log Out</Link>
                </Nav>
            </Navbar.Collapse>
        )
    }

    function guestNav() {
        return(
            <Navbar.Collapse id="basic-navbar-nav">
                <Nav className="me-auto">
                    <Link to="#">Placeholder</Link>
                </Nav>
                <Nav>
                    <Link to="/register">Register</Link>
                    <Link to="/login">Login</Link>
                </Nav>
            </Navbar.Collapse>
        )
    }

    return (
        <Navbar bg="primary" variant="dark" expand="md">
            <Container>
                <Link to="/">Flaskagram</Link>
                <Navbar.Toggle aria-controls="basic-navbar-nav" />
                {IDTokens && adminTokens ? (
                    adminNav()
                ) : IDTokens ? (
                    loggedInNav()
                ) : (
                    guestNav()
                )}
            </Container>
        </Navbar>
    )
}

export default Navigation;

好吧,如果您的本地存储中已有该项目,您可以在加载时使用 useEffect 挂钩获取它。

例如这样:

  useEffect(() => {
    const cachedUserName = JSON.parse(localStorage.getItem('username'));
    if (cachedUserName ) {
      setUserName(cachedUserName);
    }
else {
...your logic
}
  }, [setUserName]);

您不需要三个单独的上下文来存储这 3 条信息。要使您的用户对象可从您应用中的任何位置访问,请在 App.js 内添加此行(在 App 函数的开头):

const [user, setUser] = useState();

确保在 App.js 中导入了 useState 挂钩,以及从定义上下文的任何地方导入了 UserContext(在你的情况下,我相信它是 auth.js)。

然后,使用上下文提供程序包装从 App.js 返回的所有 jsx 元素,如下所示:

export default function App() {
  const [user, setUser] = useState();
  // any other code you might have here

  return (
    <UserContext.Provider value={{ user, setUser }}>
      // all your app's components here
    </UserContext.Provider>
  );
}

在 auth.js 中,这就是您所需要的:

import React from "react";

const UserContext = React.createContext();

export default UserContext;

无论您在何处设置用户对象(最有可能在您的登录页面上),只需使用以下行访问 setUser 函数(并且不要忘记导入 UserContext):

const { setUser } = useContext(UserContext);

现在,在navbar.js:

import React, { useContext } from "react";
import { Navbar, Nav, Container } from "react-bootstrap";
import { Link } from "react-router-dom";
import UserContext from "../context/auth";

function Navigation() {
  const {
    user: { username, isAdmin },
  } = useContext(UserContext);

  function adminNav() {
    return (
      <Navbar.Collapse id="basic-navbar-nav">
        <Nav className="me-auto">
          <Link to="#">Placeholder</Link>
        </Nav>
        <Nav>
          <Link to={`/${username}`}>Welcome, {username}</Link>
          <Link to="/logout">Log Out</Link>
        </Nav>
      </Navbar.Collapse>
    );
  }

  function loggedInNav() {
    return (
      <Navbar.Collapse id="basic-navbar-nav">
        <Nav className="me-auto">
          <Link to="#">Placeholder</Link>
        </Nav>
        <Nav>
          <Link to={`/${username}`}>Welcome, {username}</Link>
          <Link to="/logout">Log Out</Link>
        </Nav>
      </Navbar.Collapse>
    );
  }

  function guestNav() {
    return (
      <Navbar.Collapse id="basic-navbar-nav">
        <Nav className="me-auto">
          <Link to="#">Placeholder</Link>
        </Nav>
        <Nav>
          <Link to="/register">Register</Link>
          <Link to="/login">Login</Link>
        </Nav>
      </Navbar.Collapse>
    );
  }

  return (
    <Navbar bg="primary" variant="dark" expand="md">
      <Container>
        <Link to="/">Flaskagram</Link>
        <Navbar.Toggle aria-controls="basic-navbar-nav" />
        {username && isAdmin
          ? adminNav()
          : username
          ? loggedInNav()
          : guestNav()}
      </Container>
    </Navbar>
  );
}

export default Navigation;

为了使此实现起作用,当您登录用户时,用户对象必须设置 isAdminusername 的属性,以便可以在导航栏中访问它们。 isLoggedIn 属性 是不必要的,因为如果用户名 属性 不为空,则意味着用户必须登录。