Как отобразить страницу только после setstate

#javascript #reactjs #react-native #react-router #react-hooks

#javascript #reactjs #реагировать-родной #реагировать-маршрутизатор #реагирующие хуки

Вопрос:

Я пытаюсь создать страницу аутентификации пользователя. Здесь я пытаюсь перенаправить на домашнюю страницу, если токен уже хранится в безопасном хранилище, иначе перенаправить на страницу входа. Условие, которое я указал на странице приложения. Но когда аутентификация пользователя верна, приложение не перенаправляет на главную страницу, когда я закрываю и открываю приложение. Однако, когда я нажимаю на нового пользователя? и вернитесь на страницу входа, затем она перенаправляется на главную страницу. Я чувствую, что это что-то связанное с изменением состояния, и сначала страница отображает начальное состояние, а затем отображает измененное состояние, которое может вызывать проблему. Пожалуйста, помогите мне в этом отношении. Я вставил код для справки

App.js

 import React, {useState,useEffect} from 'react';
import {
  SafeAreaView,
  StyleSheet,
  View,
  Text,
  StatusBar
} from 'react-native';


import { NativeRouter, Route,Redirect } from 'react-router-native';
import Login from './login';
import Register from './register';
import Main from './main';
import tokenGetter from './utils/auth';

const App = () => {

const [userAuthenticated,setFlag] = useState(false);

useEffect(()=>{
   tokenGetter('token','peer','peerId').then((data)=>{
     if(data){
       setFlag(true)
     }else{
       setFlag(false)
     }
   }).catch((e)=>{
     console.log(e)
   })
},[userAuthenticated]);

 return (
  <NativeRouter>
   <StatusBar barStyle="dark-content" />
   <Route exact path="/">
   {(userAuthenticated)?<Redirect to="/main" />:<Login/>}
   </Route>
     <Route path='/login' component={Login}/>
     <Route path="/main" component={Main}/>
     <Route path="/about" component={Register}/>
   </NativeRouter>
  );
};

const styles = StyleSheet.create({
 bigBlue: {
  color: 'blue',
  fontWeight: 'bold',
  fontSize: 30,
 },
 red: {
   color: 'red',
  },
});

export default App;
  

Ответ №1:

Похоже, классический случай необходимости состояния «загрузки».

  • Добавьте isAuthenticating состояние.
  • Упростите логику установки флага, чтобы она была просто правдивой / ложной для данных.
  • При получении токена завершено, в isAuthtenticating обратном вызове установлено finally false.
  • Условно отображать перенаправление, только если в данный момент не выполняется аутентификация и пользователь аутентифицирован.

Предложение кода

 const App = () => {
  const [isAuthtenticating, setIsAuthenticating] = useState(true);
  const [userAuthenticated, setFlag] = useState(false);

  useEffect(()=>{
    tokenGetter('token','peer','peerId')
      .then((data) => {
        setFlag(!!data);
      })
      .catch((e)=>{
        console.log(e)
      })
      .finally(() => {
        setIsAuthenticating(false);
      });
  }, []);

  return (
    <NativeRouter>
      <StatusBar barStyle="dark-content" />
      <Route exact path="/">
        {(!isAuthtenticating amp;amp; userAuthenticated) ? <Redirect to="/main" />:<Login/>}
      </Route>
      <Route path='/login' component={Login}/>
      <Route path="/main" component={Main}/>
      <Route path="/about" component={Register}/>
    </NativeRouter>
  );
};
  

Ответ №2:

Проблема в том, что вы проверяете userAuthenticated и переходите к Login , если это false так, но вы не ждете, пока tokenGetter не установится. Простой способ исправить это — добавить loading состояние и дождаться, пока tokenGetter установится:

 // HERE
let [loading, setLoading] = useState(true);

useEffect(()=> {
   tokenGetter('token','peer','peerId').then((data)=>{
     setLoading(false); // <= HERE
     if (data) {
       setFlag(true);
     } else {
       setFlag(false)
     }
   }).catch((e)=>{
     setLoading(false); // <= HERE
     console.log(e)
   })
},[userAuthenticated]);

 return (
  <NativeRouter>
   <StatusBar barStyle="dark-content" />
   <Route exact path="/">
   {!loading amp;amp; (userAuthenticated ? <Redirect to="/main" />:<Login/>)}
   // ^ HERE
   </Route>
     <Route path='/login' component={Login}/>
     <Route path="/main" component={Main}/>
     <Route path="/about" component={Register}/>
   </NativeRouter>
  );
};
  

Ответ №3:

Вы можете легко использовать защищенный маршрутhttps://www.npmjs.com/package/react-protected-route-compone

 import { BrowserRouter, Switch, Route } from "react-router-dom";
import ProtectedRoute from "react-protected-route-component";

const Routes = () => {
  return (
    <BrowserRouter>
      <Switch>
        <Route path="/" component={() => <h1>UnProtected Route</h1>} exact />

        <ProtectedRoute
          path="/protected"
          redirectRoute="/"
          guardFunction={() => {
            const token = localStorage.getItem('authToken');
            if(token){
              return true;
            }else{
              return false;
            }
          }}
          component={() => <h1>Protected Route</h1>}
          exact
        />

      </Switch>
    </BrowserRouter>
  );
};

export default Routes;
  

Комментарии:

1. Я не использую react router в браузере, я использую мобильное приложение react native. Поэтому я думаю, что protectedroute недоступен в react native router.