我有一个带有子菜单的导航栏组件。登录后,导航栏的子菜单应该会发生变化。 我使用了钩子 useContext,但是当用户登录时它不会刷新导航栏组件。当我刷新页面时它工作正常。 我的代码问题在哪里?
应用组件
import React, { useState, useEffect } from "react";
import logo from "./assets/logoBusca.png";
import "./App.css";
import { Route } from "wouter";
import Home from "./components/Home";
import Login from "./components/Login";
import Post from "./components/Post";
import NavbarUser from "./components/NavbarUser";
import { AuthContext } from "./context/AuthContext";
import logic from "../src/logic";
function App() {
const [user, setUser] = useState(false);
useEffect(() => {
(async () => {
const loggedIn = await logic.isUserLoggedIn;
if (loggedIn) setUser(true);
})();
}, [user]);
return (
<AuthContext.Provider value={user}>
<div className="App">
<header className="App-header">
<div className="images">
<div className="logo">
<a href="/">
<img src={logo} alt="logo" />
</a>
</div>
<div className="user_flags">
<NavbarUser />
</div>
</div>
</header>
<Route path="/">
<Home />
</Route>
<Route path="/login">
<Login />
</Route>
<Route path="/nuevabusqueda">
<Post />
</Route>
</div>
</AuthContext.Provider>
);
}
export default App;
导航栏组件
import React, { useContext } from "react";
import userIcon from "../../assets/userIcon.png";
import { AuthContext } from "../../context/AuthContext";
export default function NavbarUser() {
const isAuthenticated = useContext(AuthContext);
return (
<>
{!isAuthenticated ? (
<div className="navbar-item has-dropdown is-hoverable">
<img src={userIcon} alt="user" />
<div className="navbar-dropdown">
<a href="/login" className="navbar-item" id="item_login">
Login
</a>
<hr className="navbar-divider" />
<a href="/registro" className="navbar-item" id="item_register">
Registro
</a>
</div>
</div>
) : (
<div className="navbar-item has-dropdown is-hoverable">
<img src={userIcon} alt="user" />
<div className="navbar-dropdown">
<a href="/datos" className="navbar-item" id="item_login">
Perfil
</a>
<hr className="navbar-divider" />
<a href="/user" className="navbar-item" id="item_register">
Logout
</a>
</div>
</div>
)}
</>
);
}
上下文组件
import { createContext } from "react";
export const AuthContext = createContext();
逻辑组件
import buscasosApi from "../data";
const logic = {
set userToken(token) {
sessionStorage.userToken = token;
},
get userToken() {
if (sessionStorage.userToken === null) return null;
if (sessionStorage.userToken === undefined) return undefined;
return sessionStorage.userToken;
},
get isUserLoggedIn() {
return this.userToken;
},
loginUser(email, password) {
return (async () => {
try {
const { token } = await buscasosApi.authenticateUser(email, password);
this.userToken = token;
} catch (error) {
throw new Error(error.message);
}
})();
},
};
export default logic;
答案 0 :(得分:1)
我认为 Login 组件不会调用 setUser(true)
这是它可能如何工作的示例。
const { useState, useEffect, createContext, useContext } = React;
const AuthContext = createContext();
const Login = () => {
const [isAuthenticated, setAuth] = useContext(AuthContext);
const onClick = () => setAuth(true);
return <button disabled={isAuthenticated} onClick={onClick}>Login</button>
}
const App = () => {
const [isAuthenticated] = useContext(AuthContext);
return <div>
<Login/>
<button disabled={!isAuthenticated}>{isAuthenticated ? "Authenticated" : "Not Authenticated"}</button>
</div>;
}
const AuthProvider = ({children}) => {
const [isAuthenticated, setAuth] = useState(false);
return <AuthContext.Provider value={[isAuthenticated, setAuth]}>
{children}
</AuthContext.Provider>;
}
ReactDOM.render(
<AuthProvider>
<App />
</AuthProvider>,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="root"></div>
答案 1 :(得分:1)
在我看来,您没有更新状态。最初您的状态是 false
。第一次渲染后,您的效果被触发,状态再次设置为 false
。之后你的效果不再运行,因为它取决于它应该改变的状态。没有状态改变 - 没有效果 - 没有状态再次改变。另外,如果状态发生变化,也会触发效果,但您不需要这样做。
您在这里的目标是构建一个能够:
要做到这一点,您需要某种方式从 logic
异步发送消息以做出反应。您可以通过某种订阅来做到这一点,如下所示:
const logic = {
set userToken(token) {
sessionStorage.userToken = token;
},
get userToken() {
if (sessionStorage.userToken === null) return null;
if (sessionStorage.userToken === undefined) return undefined;
return sessionStorage.userToken;
},
get isUserLoggedIn() {
return this.userToken;
},
loginUser(email, password) {
return (async () => {
try {
const { token } = await buscasosApi.authenticateUser(email, password);
this.userToken = token;
this.notify(true);
} catch (error) {
throw new Error(error.message);
}
})();
},
subscribers: new Set(),
subscribe(fn) {
this.subscribers.add(fn);
return () => {
this.subscribers.remove(fn);
};
},
notify(status) {
this.subscribers.forEach((fn) => fn(status));
},
};
function useAuthStatus() {
let [state, setState] = useState("checking");
let setStatus = useCallback(
(status) => setState(status ? "authenticated" : "not_authenticated"),
[setState]
);
useEffect(function () {
return logic.subscribe(setStatus);
}, []);
useEffect(function () {
setStatus(logic.isUserLoggedIn);
}, []);
return state;
}
请注意,现在有三种可能的状态 - 'checking'、'authenticated' 和 'not_authenticated'。它更详细,可以防止一些错误。例如,如果您想在用户未通过身份验证时将其重定向到登录页面。