如何正确等待这个 axios.get 请求?

Posted

技术标签:

【中文标题】如何正确等待这个 axios.get 请求?【英文标题】:How to properly await this axios.get request? 【发布时间】:2020-04-13 04:52:32 【问题描述】:

对不起,如果这是我忽略的极其简单的事情,但我正在尝试制作一个组件,该组件基本上将某些 react-router 路由限制为仅对具有活动令牌的用户。

import Axios from "axios";
import React, useState, useEffect, useSelector from 'react';
import Route, Redirect from 'react-router-dom';

function isLogin()
    const result = Axios.get('http://localhost:8081/authentication', withCredentials: true)
    .then(res => 
        console.log(res);
    )
    console.log(result);


const PrivateRoute = (component: Component, ...rest) => 

    return (
        <Route ...rest render=props => (
            isLogin() ?
                <Component ...props />
            : <Redirect to="/login" />
        ) />
    );
;

export default PrivateRoute;

似乎(如预期的那样)只有“console.log(result)”会使用未决的承诺执行,但最终结果是,我试图将一些逻辑编码到后端给出的响应中(true 或false),然后应将其发送到 PrivateRoute 组件以确定是否应将用户发送回登录等。

我知道这一定是因为 axios.get 的异步特性导致了我的问题,但我尝试了几种不同的方法:

使 isLogin 函数异步,然后等待 axios 请求

在 PrivateRoute 返回中创建另一个异步函数,带有等待。

似乎我在这里尝试的任何东西都没有正确等待 axios.get 的结果,因此会给出不需要的结果.. 非常感谢任何建议,甚至是正确的前进方向。

谢谢。

【问题讨论】:

让我们专注于期望。发送请求但尚未返回响应后,您希望看到什么? 您不能在渲染流程中直接使用异步代码。身份验证完成后更新状态。 这能回答你的问题吗? How to perform authentication with React hooks and react-router Additional information on handling auth in React 您应该在登录后将令牌存储在本地存储或cookie中。然后获取该令牌以查看用户是否已登录。不应该以这种方式使用异步逻辑 【参考方案1】:

正如@Emile Bergeron 在 cmets (引用)中所说,我将向私有 Route 组件添加一个状态,如果用户通过身份验证,它将存储该状态。这将在组件(私有路由)第一次挂载时进行检查。

作为一个代码,它看起来像这样,以您的代码为基础:

import Axios from "axios";
import React, useState, useEffect, useSelector from 'react';
import Route, Redirect from 'react-router-dom';

const PrivateRoute = (component: Component, ...rest) => 
    // State
    const [authenticated, setAuthentication] = useState(null);
    const [loadingComplete, setLoadingComplete] = useState(false);
    // Login function
    useEffect(
        () => 
            // ComponentDidMount
            // Declare Function (you can also declare it outside the useEffect, 
            //    if you want to run it also if another prop changes for instance.
            //    But it will be overwritten on every rerender; 
            //    To prevent this you could use useCallback hook)
            const isLogin = async () => 
                try 
                    const result = await Axios.get('http://localhost:8081/authentication', withCredentials: true);
                    // Store the result, e.g. ID, token, ...
                    setAuthentication(result);
                 catch (e) 
                    // Something failed
                    console.log(e);
                
                setLoadingComplete(true);
               
            // run login function
            isLogin();
        ,
        []
    );
    if(loadingComplete)
        return (
            <Route ...rest render=props => (
                !!authenticated ?
                    <Component ...props />
                : <Redirect to="/login" />
            ) />
        );
    else
        return ( <div> Loading... </div>);
    
;

export default PrivateRoute;

编辑:当然,您还需要加载过程的状态,因此在获取用户之前重定向不会影响您。

【讨论】:

我肯定是从错误的角度看待这个问题,在合并了你的大部分代码之后(尤其是使用 State 来存储这些变量的要点),它完美地工作。非常感谢你,以及所有在这里回答的人。【参考方案2】:

我已经创建了一个gist 来处理这种情况。

您需要 2 个状态。

已通过身份验证 正在加载

您将拥有一个对用户进行身份验证的函数,但在它进行身份验证时您还需要一个加载状态。

所以你会有类似的东西

return (
    <Route
        ...rest
        render=props => (
            !isLoading
                ?
                (
                    isAuthenticated
                        ?
                        <Component ...props />
                        :
                        <Redirect to="/login" />
                )
                :
                <Loading />
        )
    />
)

您将拥有一个设置这些状态的函数

useEffect(() => 
    setIsLoading(true)
    isLogin()
        .then(() => 
            setIsAuthenticated(true)
        )
        .catch(() => 
            setIsAuthenticated(false)
        )
        .then(() => 
            setIsLoading(false)
        )
, [])

【讨论】:

以上是关于如何正确等待这个 axios.get 请求?的主要内容,如果未能解决你的问题,请参考以下文章

axios怎么发送xml数据

axios如何一次性发送多个网络请求?

如何强制 axios GET 请求发送标头?

如何根据动态创建的请求数组执行多个axios get请求

为啥 axios get 方法请求发送两次?

如何使用 URL 中的路由参数执行 axios get 请求?