开发者问题收集

React 上的 Async / Await 不起作用。什么都不起作用

2020-04-14
1483

好吧,说其他一切都经过测试并且运行良好,我创建了这个 PublicRoute ,它向 NodeJS 发送请求,但函数 isAuthenticated 从不等待来自后端的响应,并且始终返回 promise 而不是 truefalse 。我在互联网上到处搜索,但没有找到解决方案。我不知道如何让它等待。

PublicRoute 文件:

import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { useAuth } from '../context/auth';
import api from '../services/api'; // Axios.

function PublicRoute( { component: Component, ...rest } ) {
    const { authTokens } = useAuth();

    async function isAuthenticated ( token ) {
        if ( token === undefined ) return false;

        const data = {
            token
        };

        try {
            const response = await api.post( '/cT', data );
            if ( response.status === 200 ) {
                console.log( 'Retorned true.' );
                return true;
            } else {
                console.log( 'Retorned false.' );
                return false;
            }

        } catch ( error ) {
            console.log( 'Retorned false with error.' );
            console.log( error );
            return false;
        };
    }

    const estaAutenticado = isAuthenticated( authTokens );

    console.log( 'Is authenticated?' );
    console.log( estaAutenticado ); // It was supposed to return true or false, but always returns a promise.

    return (
        <Route { ...rest }
            render={
                ( props ) => ( estaAutenticado === true ) ?
                    ( <Redirect to='/profile' /> ) :
                    ( <Component { ...props } /> )

            }
        />
    );
}

export default PublicRoute;

这是我的 Routes 文件:

import React, { useState } from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';

import { AuthContext } from './context/auth';

// Pages:

import PublicRoute from './pages/PublicRoute';
import PrivateRoute from './pages/PrivateRoute';
import Admin from './pages/Admin';
import Logon from './pages/Logon';
import Register from './pages/Register';
import User from './pages/Register/User';
import Ong from './pages/Register/Ong';
import Profile from './pages/Profile';
import NewIncident from './pages/NewIncident';


export default function Routes( props ) {
    const localStorageToken = localStorage.getItem( 'token' );

    let existingTokens = undefined;
    if ( localStorageToken !== 'undefined' ) {
        existingTokens = JSON.parse( localStorage.getItem( 'token' ) );
    }

    const [ authTokens, setAuthTokens ] = useState( existingTokens );

    const setTokens = ( token ) => {
        localStorage.setItem( 'token', JSON.stringify( token ) );
        setAuthTokens( token );
    };

    return (
        <AuthContext.Provider value={{ authTokens, setAuthTokens: setTokens }}>
            <BrowserRouter>
                <Switch>
                    <PublicRoute exact path='/' component={ Logon } />

                    <PublicRoute exact path='/register' component={ Register } />

                    <PublicRoute exact path='/register/ong' component={ Ong } />

                    <PublicRoute exact path='/register/user' component={ User } />


                    <PrivateRoute exact path='/administration' component={ Admin } />

                    <PrivateRoute exact path='/profile' component={ Profile } />

                    <PrivateRoute exact path='/incidents/new' component={ NewIncident } />
                </Switch>
            </BrowserRouter>
        </AuthContext.Provider>
    )
};
2个回答

isAuthenticated 是一个异步函数,因此您必须等待结果才能使用它。但情况比这更复杂。您的 PublicRoute 函数是一个 组件 ,并且组件必须同步返回您想要呈现的内容(至少在我们获得悬念之前)。由于 isAuthenticated 是异步的,这意味着您必须渲染两次:一次是在确定 isAuthenticated 的结果时,然后再次渲染。最简单的方法是使用状态:

import { useEffect, useState } from 'react';

function PublicRoute( { component: Component, ...rest } ) {
    const { authTokens } = useAuth();
    const [isAuthenticated, setIsAuthenticated] = useState(null);

    useEffect(() => {
        isAuthenticated(authTokens).then(setIsAuthenticated);

        async function isAuthenticated(token) {
            if ( token === undefined ) return false;

            try {
                const response = await api.post( '/cT', { token } );
                return response.status === 200;
            } catch ( error ) {
                console.log( 'Retorned false with error.' );
                console.log( error );
                return false;
            };
        }
    }, [authTokens]);

    console.log( 'Is authenticated?' );
    console.log( isAuthenticated ); // Will be null (unknown), true, or false

    if (isAuthenticated === null) {
        // Render nothing for now; component will re-render after auth check
        return null;
    }

    return (
        <Route { ...rest }
            render={
                ( props ) => ( isAuthenticated ) ?
                    ( <Redirect to='/profile' /> ) :
                    ( <Component { ...props } /> )

            }
        />
    );
}

您的组件现在返回 React 可以处理的内容而不是 Promise,并且它通过重新渲染来处理异步性。您的下一个重点应该是“用户在等待时应该看​​到什么?”这种采用的方法是返回 null ,因此路由不会暴露,但您可能需要考虑渲染微调器,这可能需要将此身份验证检查功能移动到组件树中的其他位置。

Jacob
2020-04-15

async 始终与 await 关键字配对:

 const estaAutenticado = await isAuthenticated( authTokens );
                         ^^^^^

现在您可以在 estaAutenticado 中访问该值。

moonwave99
2020-04-14