我有一个PrivateRoute,它可以验证令牌是否有效以及它是一个异步函数。问题是:我渲染视图的验证不起作用,它始终在渲染:
App.js
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
isAuthenticated() ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: "/", state: { from: props.location } }} />
)
}
/>
);
const Routes = () => (
<BrowserRouter>
<Fragment>
<Switch>
<Route exact path="/" component={SignIn} />
<PrivateRoute path="/app" component={App} />
</Switch>
<ModalContainer />
</Fragment>
</BrowserRouter>
);
export default Routes;
auth.js
import axios from 'axios'
export const isAuthenticated = async () => {
const isValidRequest = false;
const resp = await axios.get('http://127.0.0.1:8080...')
data = resp.data;
console.log(data);
....// more code
return isValidRequest;
}
如何确保PrivateRoute等待功能isAuthenticated()
?
更新1:
const Routes = () => {
const [state, setState] = useState({isLoading: true, authenticated: false});
useEffect(() => {
async function checkAuth() {
const isAuth = await isAuthenticated();
setState({isLoading: false, authenticated: isAuth});
}
}, []);
if(state.isLoading) {
return <div>Loading....</div>
}
return (
<BrowserRouter>
<Fragment>
<Switch>
<Route exact path="/" component={SignIn} />
<PrivateRoute path="/app" isAuthenticated={state.authenticated} component={App} />
</Switch>
<ModalContainer />
</Fragment>
</BrowserRouter>
);
}
答案 0 :(得分:1)
您无需在所有isAuthenticated
中调用PrivateRoutes
,而是在Routes component
中对其调用一次,以便只执行一次检查,然后将值作为prop传递。另请注意,在提取数据时,请保持加载状态
请注意,您的isAuthenticated
函数是异步函数,因此您必须等到诺言得到解决。您可以使用async-await
或采用传统的Promise方法
const PrivateRoute = ({ component: Component, isAuthenticated, ...rest }) => (
<Route
{...rest}
render={props =>
isAuthenticated ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: "/", state: { from: props.location } }} />
)
}
/>
);
const Routes = () => {
const [state, setState] = useState({isLoading: true, authenticated: false});
useEffect(() => {
async function checkAuth() {
const isAuth = await isAuthenticated();
setState({isLoading: false, authenticated: isAuth});
}
checkAuth();
}, []);
if(state.isLoading) {
return <Loader/>
}
return (
<BrowserRouter>
<Fragment>
<Switch>
<Route exact path="/" component={SignIn} />
<PrivateRoute path="/app" isAuthenticated={state.authenticated} component={App} />
</Switch>
<ModalContainer />
</Fragment>
</BrowserRouter>
);
}
export default Routes;
更新:由于您未使用v16.8.0或更高版本的react,因此可以通过使用类componnet来实现上述逻辑
class Routes extends React.Component {
state = {isLoading: true, authenticated: false};
async componentDidMount() {
const isAuth = await isAuthenticated();
this.setState({isLoading: false, authenticated: isAuth});
}
render() {
if(state.isLoading) {
return <Loader/>
}
return (
<BrowserRouter>
<Fragment>
<Switch>
<Route exact path="/" component={SignIn} />
<PrivateRoute path="/app" isAuthenticated={state.authenticated} component={App} />
</Switch>
<ModalContainer />
</Fragment>
</BrowserRouter>
);
}
}
export default Routes;
答案 1 :(得分:0)
可能是因为isAuthenticated()
返回了一个Promise,该Promise被视为真实值,因此三元条件将呈现该组件。
试试看:
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={async (props) => {
const authenticated = await isAuthenticated();
return authenticated ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: "/", state: { from: props.location } }} />
)
}
}
/>
);
我认为,除非render
组件的Route
道具不允许使用异步功能,否则此方法应该有效。
答案 2 :(得分:0)
我建议您存储进度并根据进度返回:
const PrivateRoute = ({ component: Component, ...rest }) => (
const [finished, setFinished] = useState(false);
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
isAuthenticated().then(result => {
setFinished(true);
setIsAuthenticated(result);
});
}, []);
<Route
{...rest}
render={props =>
finished && isAuthenticated ? (
<Component {...props} />
) : finished && !isAuthenticated ? (
<Redirect to={{ pathname: "/", state: { from: props.location } }} />
) : null
}
/>
);
答案 3 :(得分:0)
为了等待兑现承诺,您可以在isAuthenticated()
的结果为undefined
时显示加载消息:
const PrivateRoute = ({ component: Component, ...rest }) => {
const isAuthenticated = isAuthenticated();
if (isAuthenticated === undefined) {
return <p>
Loading ...
</p>
}
return isAuthenticated ?
<Route {...rest} render={props => <Component {...props}/>} /> :
<Redirect to={{ pathname: "/", state: { from: props.location } }} />
}