登录或注销重定向成功后更新导航栏



我在React中有一个简单的身份验证应用程序,问题是当用户登录时,他被重定向到他的个人资料,但我的导航栏组件没有正确渲染。仅在刷新页面后应用更改,但在请求直接重定向时不应用。

应用组件:

function App() {
const auth = useAuth();
return (
<>
<Router>
{auth.auth ? <Navbar/> : <NotAuthNavbar/>}
<Routes>
<Route path="/" element={<Dashboard/>}/>
<Route path="/login" element={<Login/>}/>
<Route path="/signup" element={<Register/>}/>
<Route path="/profile"
element={
<PrivateRoute>
<Profile/>
</PrivateRoute>
}
/>
<Route path="/confirm-register/:tokenConfirm" element={<ConfirmRegister/>}/>
<Route path="/registered" element={<RegisterMessage/>}/>
</Routes>
</Router>
</>
);
}
export default App;

授权自定义钩子:

const useAuth = () => {
const [auth,setAuth] = useState(null);
const [user,setUser] = useState({});
const isAuth = async() => {
await axios.get('http://localhost:5000/api/logged-user/',{withCredentials:true})
.then(res => {
setUser(res.data);
setAuth(true);
})
.catch(error => {
setAuth(false);
});
}

useEffect(() => {
isAuth();
},[auth])
return{
auth:auth,
user:user
}
}
export default useAuth;

导航栏和NotAuthNavbar:

///Navbar.jsx
const Navbar = () => {
const auth = useAuth();
const navigate = useNavigate();
const logout = async() =>{
await axios.get("http://localhost:5000/api/logout/",{withCredentials:true})
.then(res => {
console.log(res.data);
navigate('/login');
return;
})
}
return(
<section>
<div className="navbar">
<ul className="navbar-menu">
<li><Link to={"/dashboard"}>Dashboard</Link></li>
<li><Link to={"/profile"}>Welcome {auth.user.username}</Link></li>
<li><button type='button' onClick={logout}>Logout</button></li>
</ul>
</div>
<Outlet />
</section>
)
}
export default Navbar;
/// NotAuthNavbar.jsx
const NotAuthNavbar = () => {

return(
<section>
<div className="navbar">
<ul className="navbar-menu">
<li><Link to={"/dashboard"}>Dashboard</Link></li>
<li><Link to={"/signup"}>Sign Up</Link></li>
<li><Link to={"/login"}>Sign In</Link></li>
</ul>
</div>
<Outlet />
</section>
)
}
export default NotAuthNavbar;

当用户登录时,我用navigator by react-router-dom重定向到他的配置文件。

我不知道登录和注销后如何更新导航栏。我一直在想有一个小细节我没有看到,但我已经被困在这里几个小时了。

提前感谢。

编辑

这是登录的功能

const login = async(e) => {
e.preventDefault();
await axios.post("http://localhost:5000/api/signin/",{
email:email.email,
password:password.password
},{
withCredentials:true,
})
.then(res => {
setIsSubmitted(true);
if(res.status === 200){
alert('!LOGGED');
navigate('/profile');
return res.data;
}
})
.catch(error => {
let parsedErrors = [];
parsedErrors = JSON.parse(error.request.response);
setHandleErrors(parsedErrors);
setIsSubmitted(true);
})
}

Issue

React钩子不共享状态。

<标题>

解决方案将useAuth状态移动到React上下文中,并将其提供给应用程序。然后useAuth钩子应该使用useContext钩子来访问单个认证状态。

的例子:

创建AuthContext、provider和hook。

import { createContext, useContext, useEffect, useState } from 'react';
const AuthContext = createContext({
auth: null,
setAuth: () => {},
user: null,
});
export useAuth = () => useContext(AuthContext);
const AuthProvider = ({ children }) => {
const [auth, setAuth] = useState(null);
const [user, setUser] = useState(null);
useEffect(() => {
const isAuth = async () => {
try {
const res await axios.get(
'http://localhost:5000/api/logged-user/',
{ withCredentials: true }
);

setUser(res.data);
} catch(error) {
setUser(null);
};
};
isAuth();
}, [auth]);
return (
<AuthContext.Provider value={{ auth, setAuth, user }}>
{children}
</AuthContext.Provider>
);
};
export default AuthProvider;

AuthProvider组件包裹App组件

import AuthProvider from "../path/to/AuthContext";
...
<AuthProvider>
<App />
</AuthProvider>

现在有一个单独的authuser状态,useAuth钩子都引用相同的状态。

应用

function App() {
const { auth } = useAuth();
return (
<Router>
{auth ? <Navbar /> : <NotAuthNavbar />}
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Register />} />
<Route
path="/profile"
element={(
<PrivateRoute>
<Profile />
</PrivateRoute>
)}
/>
<Route path="/confirm-register/:tokenConfirm" element={<ConfirmRegister />} />
<Route path="/registered" element={<RegisterMessage />} />
</Routes>
</Router>
);
}

导航条

登录setAuthupdater功能,注销成功后设置auth为false。

const Navbar = () => {
const { setAuth, user } = useAuth();
const navigate = useNavigate();
const logout = async () => {
const res await axios.get(
"http://localhost:5000/api/logout/",
{ withCredentials: true }
);
console.log(res.data);
setAuth(false);
navigate('/login');
}
return(
<section>
<div className="navbar">
<ul className="navbar-menu">
<li><Link to={"/dashboard"}>Dashboard</Link></li>
<li><Link to={"/profile"}>Welcome {user.username}</Link></li>
<li><button type='button' onClick={logout}>Logout</button></li>
</ul>
</div>
<Outlet />
</section>
);
};

使用login函数的组件

使用useAuth钩子访问setAuth更新器功能,认证成功后设置auth为true

const { setAuth } = useAuth();
...
const login = async (e) => {
e.preventDefault();
try {
const res = await axios.post(
"http://localhost:5000/api/signin/",
{
email: email.email,
password: password.password
},
{
withCredentials: true,
}
);
if (res.status === 200) {
alert('!LOGGED');
setAuth(true);
navigate('/profile');
}
} catch(error) {
setHandleErrors(JSON.parse(error.request.response));
} finally {
setIsSubmitted(true);
}
}

注意:将async/await与Promise链混合是反模式的。一般来说,你应该选择其中之一。我使用async/awaittry/catch来处理被拒绝的承诺和其他可能发生的错误。

最新更新