【问题标题】:Redirection Not Working Because of Order of Executions of Functions由于函数的执行顺序,重定向不起作用
【发布时间】:2020-06-20 02:06:37
【问题描述】:

我有一个登录页面。如果登录成功并且令牌存在于本地存储中,我想重定向到私人页面/面板。我正在调用表单的 onSubmit() 上的所有函数。

我的代码如下所示:

function LoginPage (){
  const [state, setState] = useState({
    email: '',
    password: '',
  }); 

 const [submitted, setSubmitted] = useState(false);

function ShowError(){
  if (!localStorage.getItem('token'))
  {
    console.log('Login Not Successful');
  }
}

function FormSubmitted(){
  setSubmitted(true);
  console.log('Form submitted');
}

function RedirectionToPanel(){
  console.log('ha');
  if(submitted && localStorage.getItem('token')){
    console.log('FInall');
    return <Redirect to='/panel'/>
  }
}

  function submitForm(LoginMutation: any) {
    const { email, password } = state;
    if(email && password){
      LoginMutation({
        variables: {
            email: email,
            password: password,
        },
    }).then(({ data }: any) => {
      localStorage.setItem('token', data.loginEmail.accessToken);
    })
    .catch(console.log)
    }
  }

    return (
      <Mutation mutation={LoginMutation}>
        {submitted && <Redirect to='/panel'/>}
        {(LoginMutation: any) => (
          <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);
                    setState( prevState  => ({ ...prevState,   [name]: e.target.value }));  
                  };
                  return (
                    <form style={{ width: '100%' }} 
                    onSubmit={e => {e.preventDefault();
                    submitForm(LoginMutation);FormSubmitted();RedirectionToPanel()}}>
                      <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")}
                      /> 
                      {submitted && ShowError()}

                      <FormControlLabel
                        control={<Checkbox value="remember" color="primary" />}
                        label="Remember me"
                      />
                      <br />
                      <Button className='button-center'
                        type="submit"
                        disabled={!isValid || !email || !password}
                        // onClick={handleOpen}
                        style={{
                          background: '#6c74cc',
                          borderRadius: 3,
                          border: 0,
                          color: 'white',
                          height: 48,
                          padding: '0 30px'
                        }}
                      >                       
                        Submit</Button>
                    </form>
                  )
                }}
              </Formik>
            </div>
          </Container>
          )
        }
      </Mutation>
    );
}

export default LoginPage;

当我点击提交按钮时,我会检查控制台以了解 RedirectionToPanel() 函数内部发生的情况。第一次打印“Ha”,但当我第二次单击它时,“Ha”和“Finally”都打印了。但是,重定向仍然没有发生。

如果我在 Mutation 之后使用 {submitted &amp;&amp; &lt;Redirect to='/panel'/&gt;},我会在突变时收到此错误:

This JSX tag's 'children' prop expects a single child of type '(mutateFunction: MutationFunction<any, Record<string, any>>, result: MutationResult<any>) => Element | null', but multiple children were provided.ts(2746)

如果我在返回之后和突变之前使用它,我会在 && 和 } 上遇到语法错误。

【问题讨论】:

    标签: javascript reactjs typescript react-router


    【解决方案1】:

    这是因为submitFormFormSubmitted 都包含异步操作。这意味着一个接一个地调用它们,然后是 RedirectionToPanel 并不能保证它们按该顺序执行。设置令牌后,考虑使用useEffect 挂钩进行重定向。

    另外,页面没有重定向的原因是你没有将 Redirect 组件返回到 DOM 树中。您可以通过插入一个检查提交状态的条件语句来解决此问题

    //when localStorage.getItem('token') changes, execute the callback
    useEffect(() => {
        setSubmitted(true);
    }, [localStorage.getItem('token')])
    
    ...
    
    return (
    ...
        <form style={{ width: '100%' }} 
                        onSubmit={e => {e.preventDefault();
                        submitForm(LoginMutation);}}>
    ...
        //This line can be anywhere in the return. Even at the end is fine
            {submitted && <Redirect to='/panel'/>}
        <Container />
    );
    

    如果您想在不使用 useEffect 的情况下执行此操作,可以在 submitForm 中使用 setSubmitted。但即便如此,您的 DOM 中也必须有 {submitted &amp;&amp; &lt;Redirect to='/panel'/&gt;}

      function submitForm(LoginMutation: any) {
        const { email, password } = state;
        if(email && password){
          LoginMutation({
            variables: {
                email: email,
                password: password,
            },
        }).then(({ data }: any) => {
          localStorage.setItem('token', data.loginEmail.accessToken);
          setSubmitted(true);
        })
        .catch(console.log)
        }
      }
    
    return (
    ...
        <form style={{ width: '100%' }} 
                        onSubmit={e => {e.preventDefault();
                        submitForm(LoginMutation);}}>
    ...
        //This line can be anywhere in the return. Even at the end is fine
            {submitted && <Redirect to='/panel'/>}
        <Container />
    );
    

    【讨论】:

    • 但我已经在我的 RedirectToPanel 函数中使用 {submitted &amp;&amp; &lt;Redirect to='/panel'/&gt;} 来检查提交状态。它不应该工作吗?在 DOM 中我还能如何/在哪里使用它?
    • 没有useEffect就没有办法了吗?
    • 我认为您将它与submitted &amp;&amp; localStorage.getItem('token') 混淆了。 submitted &amp;&amp; localStorage.getItem('token') 是一个条件,而 {submitted &amp;&amp; &lt;Redirect to='/panel'/&gt;}submitted 是真值时插入 &lt;Redirect to='/panel'/&gt;。即不假。我将编辑我的答案以显示重定向的适当位置
    • 啊,我明白了。但是,如果我在返回后按原样使用它,我会在 && 上得到一个错误,',' expected.')' expected.ts(1005)在结束 } 括号上
    • @a125 好吧,我的错。我不知道 Mutation 组件实际上做了什么。似乎这是一个不好的地方。你可以把它放在&lt;Container/&gt;之前的最后。
    【解决方案2】:

    正如@wxker 所说,您需要在render 方法中返回&lt;Redirect&gt; 元素才能真正发生重定向。例如。 https://codesandbox.io/s/proud-rgb-d0g8e.

    【讨论】:

    • 我的问题是 setState 发生较晚,重定向功能运行较早。另外,如果我在 return() 的开头使用{submitted &amp;&amp; &lt;Redirect to='/panel'/&gt;},我会收到上述答案中的 cmets 中所述的语法错误
    猜你喜欢
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-15
    • 1970-01-01
    • 2016-02-28
    相关资源
    最近更新 更多