我正在尝试实现私有路由组件以重定向未经身份验证的用户。问题是当我渲染<PrivateRoute authenticated={this.state.isAuthenticated} path='/private' component={Panel} currentUser={this.state.currentUser}
之类的组件时,私有路由会将经过身份验证的用户重定向到登录页面,而不是转到面板。
在App.js
中,我渲染了所有路由,包括<PrivateRoute/>
,并在currentUser
中设置了isAuthenticated
和ComponentDidMount()
状态变量,但是我可以请将它们传递给PrivateRoute
。
App.js
//imports...
class App extends Component {
state = {
currentUser: null,
isAuthenticated: false,
isLoading: false
}
loadCurrentUser = () => {
this.setState({
isLoading: true
});
// imported method
getCurrentUser()
.then(response => {
this.setState({
currentUser: response,
isAuthenticated: true,
isLoading: false
});
})
.catch(error => {
console.log(error)
this.setState({
isLoading: false
});
});
}
componentDidMount() {
this.loadCurrentUser();
}
handleLogin = () => {
this.loadCurrentUser();
this.props.history.push("/");
}
render () {
return (
<React.Fragment>
<Navigation
currentUser={this.state.currentUser}
isAuthenticated={this.state.isAuthenticated}
handleLogout={this.handleLogout} />
<Switch>
<PrivateRoute
authenticated={this.state.isAuthenticated}
exact
path='/postulante'
component={Panel}
currentUser={this.state.currentUser} />
<Route
exact
path='/'
render={
(props) => <Landing {...props} />
} />
<Route
path="/login"
exact
render={
(props) => <Login onLogin={this.handleLogin} {...props} />
} />
</Switch>
</React.Fragment>
);
}
}
export default withRouter(App);
请注意,<Navigation />
组件确实可以正确获取状态变量。
PrivateRoute.js
//imports...
const PrivateRoute = ({ component: Component, authenticated, ...rest }) => (
<Route
{...rest}
render={props =>
authenticated ? (
<Component {...rest} {...props} />
) : (
<Redirect
to={{
pathname: '/login',
state: { from: props.location }
}}
/>
)
}
/>
);
export default PrivateRoute
答案 0 :(得分:1)
问题与PrivateRoute
组件首次呈现而没有来自主App组件的任何更新道具有关。
如果您不先进入任何其他路线就直接导航到PrivateRoute
路径,您将被重定向回/login
。您的PrivateRoute
会尝试在父应用的componentDidMount()
逻辑完成之前进行渲染。因此isAuthenticated被传递为false。
如果您先说Home
或Login
,然后使用Link
转到PrivateRoute
,则会出现相反的情况。
最终,这就是为什么人们使用redux之类的状态管理工具来使已认证状态在全球范围内共享,而不是通过父组件传递的原因。
尽管有一种解决方法!
请参阅沙箱以供参考:https://codesandbox.io/s/intelligent-dan-uskcy
wasInitialized
wasInitialized
逻辑之前,componentDidMount()
将为假。componentDidMount()
时间来执行和更新
isAuthenticated
值。现在让我们看一下这行:
<Route {...rest} render={props => auth === true ? <Component
{...props} /> : !wasInitialized ? "" : <Redirect to="/login" />
}
在下一次重新渲染中,isAuthenticated
将为true或
假。如果用户已通过身份验证,我们将呈现预期的组件。如果用户未通过身份验证,则转到下一个检查。现在wasInitialized将具有true值,以便check评估为false。因此,由于两项检查均未通过,因此我们重定向到/login
。
class App extends Component {
state = {
currentUser: null,
isAuthenticated: false,
isLoading: false,
wasInitialized: false
}
loadCurrentUser = () => {
this.setState({
isLoading: true
});
// imported method
getCurrentUser()
.then(response => {
this.setState({
currentUser: response,
isAuthenticated: true,
wasInitialized: true,
isLoading: false
});
})
.catch(error => {
console.log(error)
this.setState({
isLoading: false,
wasInitialized: true
});
});
}
componentDidMount() {
this.loadCurrentUser();
}
handleLogin = () => {
this.loadCurrentUser();
this.props.history.push("/");
}
render () {
return (
<React.Fragment>
<Navigation
currentUser={this.state.currentUser}
isAuthenticated={this.state.isAuthenticated}
handleLogout={this.handleLogout} />
<Switch>
<PrivateRoute
authenticated={this.state.isAuthenticated}
path='/postulante'
component={Panel}
wasInitialized={this.state.wasInitialized}
currentUser={this.state.currentUser} />
<Route
exact
path='/'
render={
(props) => <Landing {...props} />
} />
<Route
path="/login"
exact
render={
(props) => <Login onLogin={this.handleLogin} {...props} />
} />
</Switch>
</React.Fragment>
);
}
}
export default withRouter(App);
import React from "react";
import { Route, Redirect } from "react-router-dom";
const PrivateRoute = ({
component: Component,
auth,
wasInitialized,
...rest
}) => {
return (
<Route
{...rest}
render={props =>
auth === true ? (
<Component {...props} />
) : !wasInitialized ? (
""
) : (
<Redirect to="/login" />
)
}
/>
);
};
export default PrivateRoute;