Asyn c / Ожидание на React не работает. Ничего не работает - PullRequest
0 голосов
/ 15 апреля 2020

Хорошо, говоря, что все остальное было протестировано и работает нормально, я сделал это PublicRoute, которое отправляет запрос на NodeJS, но функция isAuthenticated никогда не ожидает ответа от серверной части и всегда возвращает promise вместо true или false. Я искал везде на inte rnet, но не нашел решения. Я не знаю, как заставить его ждать.

Файл 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;

Это мой файл маршрутов:

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 ]

0 голосов
/ 15 апреля 2020

isAuthenticated - это асинхронная c функция, поэтому вам придется дождаться результата, прежде чем ее можно будет использовать. Но это сложнее, чем это. Ваша PublicRoute функция является компонентом , и компоненты должны синхронно возвращать контент, который вы хотите визуализировать (по крайней мере, пока мы не получим приостановку). Поскольку isAuthenticated является асинхронным c, это означает, что вы должны визуализировать дважды: один раз, когда определяется результат 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, чтобы маршрут не отображался, но вы можете рассмотреть возможность рендеринга счетчиков, для которых может потребоваться перемещение этой функции проверки подлинности куда-нибудь еще в дереве компонентов.

0 голосов
/ 15 апреля 2020

async всегда связан с ключевым словом await:

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

Теперь вы можете получить доступ к значению в estaAutenticado.

...