我的项目中有一个导航栏,我从App.js
内部调用它。根据我是否登录,我想渲染不同的NavBar
视图。如果登录,我希望NavBar
有一个注销按钮。如果注销,我希望NavBar
有登录按钮。我在localStorage
中使用令牌来检查我是否已登录。登录后,令牌存在于localStorage
中。注销时/登录前,localStorage
中没有令牌密钥。我将此令牌作为状态传递给NavBar
如下所示:
export default function App() {
const [loggedIn, setLoggedIn] = useState(localStorage.getItem("token"));
return (
<div>
<Router>
<Navbar isAuth={loggedIn} />
<Route exact path="/" exact component={Home} />
<Route path="/login" component={Login} />
<PrivateRoute path="/dashboard" component={Dashboard} />
</Router>
</div>
);
}
现在从NavBar
组件开始,我使用此 prop 来渲染不同的NavBar
视图,如下所示:
const NavBar = props => {
const classes = useStyles();
if (props.isAuth !== null) {
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<Typography variant="h6" className={classes.title}>
<Link
href="/"
style={{ textDecoration: "none", color: "white" }}
>
Timetracker
</Link>
</Typography>
<Link href="/" style={{ color: "white" }}>
<Button color="inherit" onClick={auth.logout}>
Logout
</Button>
</Link>
</Toolbar>
</AppBar>
</div>
);
} else {
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<Typography variant="h6" className={classes.title}>
<Link
href="/"
style={{ textDecoration: "none", color: "white" }}
>
Timetracker
</Link>
</Typography>
<Link href="/login" style={{ color: "white" }}>
<Button color="inherit">Login</Button>
</Link>
</Toolbar>
</AppBar>
</div>
);
}
};
export default NavBar;
问题是,NavBar
不会在我登录后立即更新。我必须手动刷新页面才能呈现新NavBar
。同样,在注销时,它不会自行更新,仅在手动刷新时更新。问题是什么以及如何解决这个问题?
我找到了一个简单的解决方案: 使用 componentDidMount(( 或 useEffect(( 函数,该函数将在加载导航栏页面时自动呈现。 在此函数中,使用 setInterval(( 函数持续检索身份验证状态(例如,间隔 5000(。这将不断刷新导航栏,并立即更改按钮。 我想您必须将身份验证检查放在 NavBar 组件本身中,而不是使用 props。我将要更改的特定按钮放在一个名为 NavBarUser 的单独组件中,该组件更改"登录 |注册"以"注销"并包含用户头像。然后,我将这个组件插入到导航栏本身的适当位置。 这是我的代码的样子: ``` 从 'react' 导入 React, { useState, useEffect }; 从"./头像"导入头像; 从 'react-router-dom' 导入 { 浏览器路由器作为路由器, 链接 }
;const NavBarUser = () => {
const [user, setUser] = useState({});
useEffect(() => {
{ /*
setInterval was used in order to refresh the page constantly
in order to have the "logout" button show immediately in place of
"login", as soon as user logs out.
*/}
setInterval(() => {
const userString = localStorage.getItem("user");
const user = JSON.parse(userString);
setUser(user);
}, [])
}, 5000);
const logout = () => {
return localStorage.removeItem("user");
}
if (!user) {
return (
<div className="navbar-nav ml-auto">
<Link to="/login" className="nav-item nav-link">Login</Link> <span
className="nav-item nav-link">|</span> <Link to="/SignUp" className="nav-item nav-
link">Sign Up</Link>
</div>
)
}
if (user) {
return (
<div className="navbar-nav ml-auto">
<Link to="/" className="nav-item nav-link" onClick={logout}>Logout</Link>
<Avatar img="/images/Eat-healthy.jpg" />
</div>
)
}
}
export default NavBarUser;
```
您还需要添加<Switch>
。从文档中:
呈现第一个子项或与位置匹配的子项。
<Switch>
的独特之处在于它以独占方式呈现路由。相比之下,与位置匹配的每个<Route>
都会以包容性方式呈现。
就像下面这样:
<Router>
<Switch>
<Navbar isAuth={loggedIn} />
<Route exact path="/" exact component={Home} />
<Route path="/login" component={Login} />
<PrivateRoute path="/dashboard" component={Dashboard} />
</Switch>
</Router>
在此处进一步阅读: 路由器
我希望这有所帮助!
如果你在本地存储中更改token
的值,应用的状态不会更新。
您需要确保更新状态,如果有帮助,我已经添加了一个沙盒。
这是我解决这个问题的方法:
首先,我在App
类中创建了一个isLoggedIn
状态。我给了它一个componentDidMount()
的方法,可以在应用程序启动时从cookie中获取登录状态。然后,我创建了globalLogin
和globalLogout
方法作为箭头函数,这些方法相应地将isLoggedIn
状态设置为 true 或 false。我将Nav
组件作为道具传递了isLoggedIn
状态,并传递了Login
和Nav
路由globalLogin
和globalLogout
方法。然后可以使用this.props.globalLogout();
或this.props.globalLogin();
从Login
或Nav
调用这些方法。
这是我App.js
的简化版本。
class App extends Component {
constructor(props){
super(props);
this.state = {
isLoggedIn: false,
}
}
componentDidMount() {
const token = Cookie.get("token") ? Cookie.get("token") : null;
if (token) {
this.setState({ "isLoggedIn": true });
}
}
globalLogin = () => {
this.setState({ "isLoggedIn": true });
}
globalLogout = () => {
this.setState({ "isLoggedIn": false });
}
render() {
return (
<Router>
<div className="App">
<Nav isLoggedIn={this.state.isLoggedIn} globalLogout={this.globalLogout}/>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/login" exact>
<Login globalLogin={this.globalLogin}/>
</Route>
</Switch>
</div>
</Router>
);
}
}
编辑:使用history.push在上面的登录模块中不起作用,所以我添加了一个中间体来处理道具
render() {
const LoginIntermediate = (props) => {
return (
<Login {...props} globalLogin={this.globalLogin}/>
)
}
return (
<Router>
<div className="App">
<Nav isLoggedIn={this.state.isLoggedIn} globalLogout={this.globalLogout}/>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/login" exact component={LoginIntermediate} />
</Switch>
</div>
</Router>
);
}