我有这个PrivateRoute
组件(来自文档):
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
isAuthenticated ? (
<Component {...props}/>
) : (
<Redirect to={{
pathname: '/login',
state: { from: props.location }
}}/>
)
)}/>
)
我想将isAuthenticated
更改为aysnc请求isAuthenticated()
。但是,在响应返回之前,页面重定向。
为了澄清,已经设置了isAuthenticated
功能。
如何在决定显示什么之前等待异步调用完成?
答案 0 :(得分:13)
如果您没有使用Redux或任何其他类型的状态管理模式,则可以使用Redirect
组件和组件状态来确定页面是否应呈现。这包括将状态设置为加载状态,进行异步调用,请求完成后保存用户,或者缺少用户说明和呈现Redirect
组件,如果不满足条件,组件将重定向。
class PrivateRoute extends React.Component {
state = {
loading: true,
isAuthenticated: false,
}
componentDidMount() {
asyncCall().then((isAuthenticated) => {
this.setState({
loading: false,
isAuthenticated,
});
});
}
render() {
const { component: Component, ...rest } = this.props;
if (this.state.loading) {
return <div>LOADING</div>;
} else {
return (
<Route {...rest} render={props => (
<div>
{!this.state.isAuthenticated && <Redirect to={{ pathname: '/login', state: { from: this.props.location } }} />}
<Component {...this.props} />
</div>
)}
/>
)
}
}
}
答案 1 :(得分:4)
@ pizza-r0b的解决方案非常适合我。但是,我必须稍微修改解决方案,以防止加载div被多次显示(对于app中定义的每个PrivateRoute一次),方法是将加载div放在内部 - 而不是外部 - 路由(类似于React Router's auth example ):
class PrivateRoute extends React.Component {
constructor(props) {
super(props)
this.state = {
loading: true,
isAuthenticated: false
}
}
componentDidMount() {
asyncCall().then((isAuthenticated) => {
this.setState({
loading: false,
isAuthenticated
})
})
}
render() {
const { component: Component, ...rest } = this.props
return (
<Route
{...rest}
render={props =>
this.state.isAuthenticated ? (
<Component {...props} />
) : (
this.state.loading ? (
<div>LOADING</div>
) : (
<Redirect to={{ pathname: '/login', state: { from: this.props.location } }} />
)
)
}
/>
)
}
}
我的App.js摘录完整性:
<DashboardLayout>
<PrivateRoute exact path="/status" component={Status} />
<PrivateRoute exact path="/account" component={Account} />
</DashboardLayout>
答案 2 :(得分:4)
如果有人对使用钩子而不是类组件的@CraigMyles实现感兴趣:
export const PrivateRoute = (props) => {
const [loading, setLoading] = useState(true);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const { component: Component, ...rest } = props;
useEffect(() => {
const fetchData = async () => {
const result = await asynCall();
setIsAuthenticated(result);
setLoading(false);
};
fetchData();
}, []);
return (
<Route
{...rest}
render={() =>
isAuthenticated ? (
<Component {...props} />
) : loading ? (
<div>LOADING...</div>
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location },
}}
/>
)
}
/>
);
};
与以下设备配合使用时效果很好:
<PrivateRoute path="/routeA" component={ComponentA} />
<PrivateRoute path="/routeB" component={ComponentB} />