#javascript #reactjs #navigationbar #react-context #session-storage
Вопрос:
У меня есть две вещи, которые я хотел бы знать: во-первых, панель навигации моего приложения неправильно обновляется на гостевой панели навигации при выходе из системы, но обновляется на панели навигации пользователя, когда в нее входит учетная запись, не являющаяся администратором. Если я обновлю страницу (F5) после выхода из системы, она обновится обратно на гостевую навигационную панель, но это противоречит цели того, чтобы это было SPA (одностраничное приложение).
Второе, что я хотел бы знать, это то, что в настоящее время мое приложение использует контекст React и хранилище сеансов для аутентификации, но я использую хранилище сеансов только для фактического получения информации для панели навигации. Причина в том, что хранилище сеансов фактически сохраняет информацию после обновления страницы, в то время как контекст React забывает ее. Лучше ли использовать хранилище сеансов для аутентификации пользователей в приложении React или мне следует просто использовать контекст React?
auth.js:
import { createContext, useContext } from "react";
export const AuthContext = createContext();
export function useAuth() {
return useContext(AuthContext);
}
App.js:
import { useState, useEffect } from "react";
import { BrowserRouter as Router } from "react-router-dom";
import { AuthContext } from './context/auth';
import "bootstrap/dist/css/bootstrap.min.css";
/* Begin Import Components */
import NavigationBar from "./components/navbar";
import Public from "./components/public-components/public";
/* End Import Components */
function App(props) {
const [currentUser, setCurrentUser] = useState();
// Temporary for testing
const [currentTime, setCurrentTime] = useState(0);
useEffect(() => {
fetch('/time').then(res => res.json()).then(data => {
setCurrentTime(data.time);
});
}, []);
const setAuth = (data) => {
if(data) {
sessionStorage.setItem('username', data.username);
sessionStorage.setItem('isAdmin', data.isAdmin);
setCurrentUser({username: data.username, isAdmin: data.isAdmin});
console.log('Data in setAuth: ', data);
} else {
sessionStorage.setItem('username', null);
sessionStorage.setItem('isAdmin', null);
}
}
return (
<AuthContext.Provider value={{ currentUser, setCurrentUser: setAuth }}>
<Router>
<NavigationBar />
<div className="container text-center">
<Public />
<p>The current time is {currentTime}.</p>
</div>
</Router>
</AuthContext.Provider>
);
}
export default App;
navbar.js:
import { Navbar, Nav, Container } from 'react-bootstrap';
import { Link } from "react-router-dom";
function Navigation(props) {
const username = sessionStorage.getItem('username');
const isAdmin = sessionStorage.getItem('isAdmin');
const styledNavLink = {
textDecoration: "none",
color: "#F5F5F5",
marginLeft: "10px",
marginTop: "5px"
}
const styledHeader = {
textDecoration: "none",
color: "#FFF",
fontSize: "1.5em"
}
function adminNav() {
return (
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Link to="#" style={styledNavLink}>Admin</Link>
</Nav>
<Nav>
<Link to={`/${username}`}>Welcome, {username}</Link>
<Link to="/logout" style={styledNavLink}>Log Out</Link>
</Nav>
</Navbar.Collapse>
)
}
function loggedInNav() {
return (
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Link to="#" style={styledNavLink}>User</Link>
</Nav>
<Nav>
<Link to={`/${username}`} style={styledNavLink}>Welcome, {username}</Link>
<Link to="/logout" style={styledNavLink}>Log Out</Link>
</Nav>
</Navbar.Collapse>
)
}
function guestNav() {
return(
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Link to="#" style={styledNavLink}>Guest</Link>
</Nav>
<Nav>
<Link to="/register" style={styledNavLink}>Register</Link>
<Link to="/login" style={styledNavLink}>Login</Link>
</Nav>
</Navbar.Collapse>
)
}
return (
<Navbar bg="primary" variant="dark" expand="md">
<Container>
<Link to="/" style={styledHeader}>Flaskagram</Link>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
{username !== 'null'
?
isAdmin === 'true'
?
adminNav()
: loggedInNav()
: guestNav()
}
</Container>
</Navbar>
)
}
export default Navigation;
login.js:
import { useState } from 'react';
import { Link, Redirect } from 'react-router-dom';
import { useAuth } from '../../context/auth';
import { Col, Form, Row, Button } from 'react-bootstrap';
function Login(props) {
const [loggedIn, setLoggedIn] = useState(false);
const [isError, setIsError] = useState(false);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const { setCurrentUser } = useAuth();
let referer;
if(props.location.state !== undefined) {
referer = props.location.state.referer;
} else {
referer = "/";
}
function postLogin() {
const formData = new FormData();
formData.append('email', email);
formData.append('password', password);
fetch('/login', {
method: 'post',
body: formData
}).then(res => res.json())
.then(data => {
if(data.wrongPassword) {
setIsError(true);
} else {
setCurrentUser({username: data.user.username, isAdmin: data.user.isAdmin});
setLoggedIn(true);
}
}).catch(err => {
console.log(err);
setIsError(true);
});;
}
if(loggedIn) {
return <Redirect to={referer} />;
}
return (
<main>
<header>
<h2>Login</h2>
</header>
<section>
<Form>
<Row className="justify-content-sm-center">
<Form.Group as={Col} sm={{ span: 6 }}>
<Form.Label htmlFor="email">Email</Form.Label>
<Form.Control
controlid="email"
type="email"
value={email}
onChange={e => {
setEmail(e.target.value);
}}
placeholder="Enter email"
autoFocus
/>
</Form.Group>
</Row>
<Row className="justify-content-sm-center">
<Form.Group as={Col} sm={{ span: 6 }}>
<Form.Label htmlFor="password">Password</Form.Label>
<Form.Control
controlid="password"
type="password"
value={password}
onChange={e => {
setPassword(e.target.value);
}}
placeholder="Enter password"
/>
</Form.Group>
</Row>
<Button onClick={postLogin} variant="success">Login</Button>
</Form>
</section>
<Link to="/register">Don't have an account?</Link>
{ isError amp;amp;<p>There was a problem logging in!</p> }
</main>
)
}
export default Login;
logout.js:
import { useState, useEffect } from 'react';
import { Redirect } from 'react-router-dom';
import { useAuth } from '../../context/auth';
function Logout(props) {
const [isLoggedIn, setisLoggedIn] = useState(true);
const { setCurrentUser } = useAuth();
useEffect(() => {
setCurrentUser();
setisLoggedIn(false);
}, [ setCurrentUser ]);
if(!isLoggedIn) {
return <Redirect to={"/"} />;
}
return (
<div></div>
);
}
export default Logout;
Ответ №1:
Когда происходит выход из системы, вам нужно удалить элементы, которые вы задаете в SessionStorage
Logout
компоненте следующим образом.
import { useState, useEffect } from 'react';
import { Redirect } from 'react-router-dom';
import { useAuth } from '../../context/auth';
function Logout(props) {
const [isLoggedIn, setisLoggedIn] = useState(true);
const { setCurrentUser } = useAuth();
useEffect(() => {
setCurrentUser();
/* remove session storage items */
sessionStorage.removeItem('username');
sessionStorage.removeItem('isAdmin');
setisLoggedIn(false);
}, [ setCurrentUser ]);
if(!isLoggedIn) {
return <Redirect to={"/"} />;
}
return (
<div></div>
);
}
export default Logout;
В вашем navBar.js
файле, чтобы проверить, является ли userName
он пустым, затем используйте !!userName
, чтобы проверить, является ли он null
пустым или undefined
.
Поэтому обновите return
Navigation
компонент navBar.js
файла следующим образом.
return (
<Navbar bg="primary" variant="dark" expand="md">
<Container>
<Link to="/" style={styledHeader}>Flaskagram</Link>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
{!!username
?
isAdmin === 'true'
?
adminNav()
: loggedInNav()
: guestNav()
}
</Container>
</Navbar>
)
Комментарии:
1. К сожалению, после того, как я применил две новые строки кода, проблема все еще оставалась той же
2. Можете ли вы сказать мне, что
navBar
он показывает, когда пользователь выходит из системы, как вы говорите в своей проблеме ? Я считаю, что это должно быть илиadminNav
илиloggedInNav
? И я также обнаружил еще одну проблему вNavigation
компоненте.3. Не могли бы вы, пожалуйста, проверить, что я обновил, и сказать мне, работает это или нет ? А также скажите мне, что
navBar
вы видите, когда выходите из системы, если проблема все еще существует.4. Я обновил «имя пользователя» в разделе return() до «!!имя пользователя», но у меня все еще та же проблема. Когда я впервые начинаю выходить из системы, появляется гостевая навигационная панель, а хранилище сеансов пусто, как и предполагалось. После того, как я войду в систему, страница перейдет со страницы входа на корневую страницу, появится панель навигации для входа в систему, хранилище сеансов установит «имя пользователя» на «пользователь» и установит «isAdmin» на «ложь». Когда я выхожу из системы, хранилище сеансов отключается и возвращается на корневую страницу, но панель навигации, вошедшая в систему, остается, если я не обновлю страницу полностью. Только после этого он снова правильно обновится на гостевой навигационной панели
5. Нашел проблему. Посмотрите на ответ, который я опубликовал ниже.
Ответ №2:
Нашел проблему. Проблема заключалась setAuth()
в том, что App.js. Я не обновлял контекст при выходе из системы (когда data
не было определено в инструкции if/else), поэтому панель навигации оставалась в состоянии входа в систему из-за этого.
обновлено значение setAuth в App.js:
const setAuth = (data) => {
if(data) {
sessionStorage.setItem('username', data.username);
sessionStorage.setItem('isAdmin', data.isAdmin);
setCurrentUser({username: data.username, isAdmin: data.isAdmin});
} else {
sessionStorage.removeItem('username');
sessionStorage.removeItem('isAdmin');
setCurrentUser();
}
}