如何在 React.JS 中登录/注销时更改导航栏文本?



我的项目中有一个导航栏,我从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中获取登录状态。然后,我创建了globalLoginglobalLogout方法作为箭头函数,这些方法相应地将isLoggedIn状态设置为 true 或 false。我将Nav组件作为道具传递了isLoggedIn状态,并传递了LoginNav路由globalLoginglobalLogout方法。然后可以使用this.props.globalLogout();this.props.globalLogin();LoginNav调用这些方法。

这是我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>
);
}

相关内容

  • 没有找到相关文章

最新更新