Проблема в перенаправлении с экрана входа - PullRequest
0 голосов
/ 22 марта 2020

Когда форма отправлена, я запускаю мутацию GraphQL. В случае успеха я хочу перенаправить на личную страницу /panel после того, как токен будет возвращен и сохранен в локальном хранилище. Если нет, я хочу показать сообщение об ошибке от моей StatusMessage() функции.

Проблема заключается в том, что, если вход не выполнен, сообщение об ошибке работает нормально. Но если вход успешен, я все еще перенаправлен на /404 вместо /panel. Однако когда я go возвращаюсь на свою страницу /login, на этот раз я автоматически перенаправляюсь на /panel. Я не знаю, что пойдет не так в первый раз. Может быть, токен возвращается на несколько секунд позже, а перенаправление происходит раньше?

Есть ли решение для этого? Вот мой код:

function LoginPage (props: any){

  const [isSubmitted, setIsSubmitted] = useState(false);
  const [errorMessage, setErrorMessage] = useState('');
  const [shouldRedirect, setShouldRedirect] = useState(false);

  const [removeUser] = useMutation(LoginMutation);

 // useEffect(() => {
  // if(localStorage.getItem('token')){
  //     setShouldRedirect(true);
 // },[] );


   function submitForm(email: string, password: string) {
     setIsSubmitted(true);
       removeUser({
         variables: {
             email: email,
             password: password,
         },
     }).then(({ data }: any) => {
       localStorage.setItem('token', data.loginEmail.accessToken);
       setShouldRedirect(true);
       //props.history.push("/panel");
     })
     .catch((error: { message: string; }) => {
       setShouldRedirect(false);
       console.log("Error msg:" + error.message);
       setErrorMessage(error.message);
     })
   }
   if(shouldRedirect) return <Redirect to="/panel" />;
     return (
           <Container component="main" maxWidth="xs">
             <CssBaseline />
             <div style={{
               display: 'flex',
               flexDirection: 'column',
               alignItems: 'center'
             }}>
               <Avatar>
                 <LockOutlinedIcon />
               </Avatar>
               <Typography component="h1" variant="h5">
                 Sign in
               </Typography>
               <Formik
                 initialValues={{ email: '', password: '' }}
                 onSubmit={(values, actions) => {
                   setTimeout(() => {
                     alert(JSON.stringify(values, null, 2));
                     actions.setSubmitting(false);
                   }, 1000);
                 }}
                 validationSchema={schema}
               >
                 {props => {
                   const {
                     values: { email, password },
                     errors,
                     touched,
                     handleChange,
                     isValid,
                     setFieldTouched
                   } = props;
                   const change = (name: string, e: any) => {
                     e.persist();                
                     handleChange(e);
                     setFieldTouched(name, true, false);
                   };
                   return (
                     <form style={{ width: '100%' }} 
                     onSubmit={e => {e.preventDefault();
                     submitForm(email, password);}}>
                       <TextField
                         variant="outlined"
                         margin="normal"
                         id="email"
                         fullWidth
                         name="email"
                         helperText={touched.email ? errors.email : ""}
                         error={touched.email && Boolean(errors.email)}
                         label="Email"     
                         value={email}
                         onChange={change.bind(null, "email")}
                       />
                       <TextField
                         variant="outlined"
                         margin="normal"
                         fullWidth
                         id="password"
                         name="password"
                         helperText={touched.password ? errors.password : ""}
                         error={touched.password && Boolean(errors.password)}
                         label="Password"
                         type="password"
                         value={password}
                         onChange={change.bind(null, "password")}
                       /> 
                       {isSubmitted && StatusMessage(shouldRedirect, errorMessage)}

                       <FormControlLabel
                         control={<Checkbox value="remember" color="primary" />}
                         label="Remember me"
                       />
                       <br />
                       <Button className='button-center'
                         type="submit"
                         disabled={!isValid || !email || !password}
                       >                       
                         Submit</Button>
                       <br></br>
                       <Grid container>
                         <Grid item xs>
                           <Link href="#" variant="body2">
                             Forgot password?
                           </Link>               
                       </Grid>
                     </form>
                   )
                 }}
               </Formik>
             </div>
             {/* {submitted && <Redirect to='/panel'/>} */}
           </Container>
     );
 }

 export default LoginPage;

Редактировать: Вот как я делаю приватную маршрутизацию:

const token = localStorage.getItem('token');

export const PrivateRoute = ({component, isAuthenticated, ...rest}: any) => {
    const routeComponent = (props: any) => (
        isAuthenticated
            ? React.createElement(component, props)
            : <Redirect to={{pathname: '/404'}}/>
    );
    return <Route {...rest} render={routeComponent}/>;
  };

export default function App() {
  return (
    <div>
      <BrowserRouter>
      <Switch>
      <Route exact path='/' component= {HomePage}></Route>
      <Route path='/login' component= {LoginPage}></Route>
      <PrivateRoute
      path='/panel'
      isAuthenticated={token}
      component={PanelHomePage}
      />
      <Redirect from='*' to='/404' />
      </Switch>
      </BrowserRouter>
    </div>
  );
}

1 Ответ

1 голос
/ 22 марта 2020

Вы читаете токен только при загрузке скрипта. Поэтому, когда пользователь входит в приложение через форму входа, он перенаправляется на 404, потому что вы не перечитываете токен из localalstorage. Как только вы обновите страницу sh, у вас будет токен, и поэтому пользователь получит логин.

Это, однако, не решит все ваши проблемы, потому что вы не переопределяете приложение. Вы должны проверить isLoggedIn где-нибудь в приложении, чтобы убедиться, что вы переопределили компонент.

...