验证了用户的令牌后,我将把用户信息设置到localStorage中。"isLoggedIn()";函数将检索用户信息,以决定用户是否应该继续。
我遇到的问题是私有路由将在信息设置为localStorage之前首先渲染,因此"isLoggedIn()"函数将首先返回空localStorage,我必须重新加载/刷新才能成功登录。
下面是我的代码片段,这个项目对我来说非常重要,我必须尽快完成它。我真的希望我能得到任何人的帮助。提前谢谢大家。
Index.js
const Index = () => {
return (
<div>
<Router>
<PrivateRoute path="/" component={Dashboard} />
<PrivateRoute path="/upload" component={Upload} />
<PrivateRoute path="/settings" component={Settings} />
<PrivateRoute path="/agents" component={Agents} />
<PrivateRoute path="/statistics" component={Statistics} />
<Login path="/login" />
</Router>
</div>
)
}
PrivateRoute.js
const PrivateRoute = ({ component: Component, location, ...rest }) => {
if (!isLoggedIn() && location.pathname !== `/login`) {
navigate("/login")
return null
}
return <Component {...rest} />
}
Auth.js
export const isBrowser = () => typeof window !== "undefined"
export const getUser = () =>
isBrowser() && window.localStorage.getItem("user")
? JSON.parse(window.localStorage.getItem("user"))
: {}
export const setUser = user =>
window.localStorage.setItem("user", JSON.stringify(user))
export const handleLogin = async ({ email, password }) => {
const loginUser = { email, password };
const loginResponse = await Axios.post("http://localhost:5000/api/users/login", loginUser);
if (loginResponse) {
localStorage.setItem("auth-token", loginResponse.data.token);
let token = localStorage.getItem("auth-token");
if (token === null) {
localStorage.setItem("auth-token", "");
token = "";
}
const tokenResponse = await Axios.post('http://localhost:5000/api/users/tokenIsValid', null, { headers: { "x-auth-token": token } });
if (tokenResponse.data) {
const userRes = await Axios.get("http://localhost:5000/api/users/", {
headers: { "x-auth-token": token },
});
return setUser({
username: userRes.data.displayName
})
}
}
return false
}
export const isLoggedIn = () => {
const user = getUser();
return !!user.username;
}
export const logout = callback => {
setUser({})
localStorage.setItem("auth-token", "");
callback()
}
loginComponent.js
class loginComponent extends React.Component {
state = {
email: "",
password: "",
//sessionStay: "false"
}
handleSubmit = event => {
event.preventDefault()
handleLogin(this.state)
}
render() {
if (isLoggedIn()) {
if (typeof window !== "undefined") {
navigate(`/`)
}
}
return (
<div className="login-component-wrapper">
<img src={logo} className="login-logo" alt="logo" />
<h2>Agent Reporting Dashboard</h2>
<form className="login-form">
<div className="login-form-wrapper">
<label className="form-field-label" htmlFor="email">
Email:{" "}
</label>
<input
className="form-field"
name="email"
type="email"
onChange={e => {
this.setState({ email: e.target.value })
}}
onKeyPress={e => {
if (e.key === "Enter") {
this.handleSubmit(e)
navigate(`/`)
}
}}
value={this.state.email}
/>
<label className="form-field-label" htmlFor="password">
Password:{" "}
</label>
<input
className="form-field"
name="password"
type="password"
onChange={e => {
this.setState({ password: e.target.value })
}}
onKeyPress={e => {
if (e.key === "Enter") {
this.handleSubmit(e)
navigate(`/`)
}
}}
value={this.state.password}
/>
<input
type="checkbox"
name="session-stay"
onChange={e => {
this.setState({ sessionStay: e.target.value })
}}
value="true"
/>
<label className="form-field-label" htmlFor="session-stay">
Keep me logged in
</label>
<br />
<button
type="button"
className="login-button btn-primary"
onClick={event => {
this.handleSubmit(event)
navigate(`/`)
}}
>
Login
</button>
</div>
</form>
</div>
)
}
}
磁盘操作(如设置localStorage
)是异步的,因为它需要一些时间来执行,这取决于PC,网络等。
如果没有CodeSandbox,很难猜测代码将如何表现,但对我来说,这似乎是一个异步问题。您可以尝试添加如下内容:
export const handleLogin = async ({ email, password }) => {
const loginUser = { email, password };
const loginResponse = await Axios.post("http://localhost:5000/api/users/login", loginUser);
if (loginResponse) {
await localStorage.setItem("auth-token", loginResponse.data.token);
let token = await localStorage.getItem("auth-token");
if (token === null) {
await localStorage.setItem("auth-token", "");
token = "";
}
const tokenResponse = await Axios.post('http://localhost:5000/api/users/tokenIsValid', null, { headers: { "x-auth-token": token } });
if (tokenResponse.data) {
const userRes = await Axios.get("http://localhost:5000/api/users/", {
headers: { "x-auth-token": token },
});
return setUser({
username: userRes.data.displayName
})
}
}
return false
}
注意asynchandleLogin
函数里面的await