当我try 登录时,Redux reducers会正确更新状态,但是登录页面不会立即导航到主页.但是,如果我再次点击登录按钮,它就会导航到主页.后端似乎工作正常,当我判断Redux—DevTools时,它显示状态已经正确更新.当我登录时,handleLogin外部的isAuthenticated退出true,但handleLogin内部的isAuthenticated退出false.

请注意,情况并非如此.

import React, { useEffect } from "react";
import "./login.css";
import store from "../../store/store";

import { Form, Formik, Field } from "formik";
import { TextField, Button, CircularProgress } from "@mui/material";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";

import { loginUser } from "../../store/auth/auth.actions";

import * as Yup from "yup";

export default function Login() {
  const navigate = useNavigate();
  const dispatch = useDispatch();
  const isAuthenticated = useSelector((state) => state.auth.isAuthenticated);
  // console.log(isAuthenticated);

  const handleLogin = async (credentials) => {
    await dispatch(loginUser(credentials));
    // console.log(isAuthenticated);
    // const {
    //   auth: { isAuthenticated },
    // } = store.getState();

    if (isAuthenticated) {
      navigate("/");
    }
  };

  const validationSchema = Yup.object().shape({
    username: Yup.string().required("Username is required"),
    password: Yup.string().required("Password is required"),
  });

  return (
    <main className="login-page">
      <section className="picture-container">
        <img
          src={process.env.PUBLIC_URL + "/images/login.jpg"}
          alt="decoration"
        />
      </section>
      <section className="login-section">
        <section className="login-title">
          <h1>Login</h1>
          <h3>Log into CMUniversity</h3>
        </section>
        <Formik
          initialValues={{ username: "", password: "" }}
          validationSchema={validationSchema}
          initialErrors={{ username: "" }}
          onSubmit={async (values) => {
            await handleLogin(values);
          }}
        >
          {({ errors, touched, isValid }) => (
            <Form className="login-form">
              <Field
                as={TextField}
                type="text"
                label="Username"
                name="username"
                error={touched.username && !!errors.username}
                helperText={touched.username && errors.username}
                required
                className="form-group"
              />
              <Field
                as={TextField}
                type="password"
                label="Password"
                name="password"
                error={touched.password && !!errors.password}
                helperText={touched.password && errors.password}
                className="form-group"
                required
              />
              <span className="credentials">
                Forgot your <span className="active">username</span> or{" "}
                <span className="active">password</span>
              </span>
              <Button
                type="submit"
                variant="contained"
                className="submitButton"
                disabled={!isValid}
              >
                {/* {loading ? (<CircularProgress />):("Log in")} */}
                Log In
              </Button>
              {/* Display error message if login failed */}
              {/* {error && <p className="error-message">{error}</p>} */}
              <section className="social-login">
                <p>Or log in using: </p>
                <Button
                  type="button"
                  variant="contained"
                  className="googleButton"
                >
                  <img
                    src={process.env.PUBLIC_URL + "/images/google.png"}
                    alt="Sign in with Google"
                  />
                </Button>
                <Button
                  type="button"
                  variant="contained"
                  className="facebookButton"
                >
                  <img
                    src={process.env.PUBLIC_URL + "/images/facebook.png"}
                    alt="Sign in with Facebook"
                  />
                </Button>
              </section>
              <span className="credentials">
                Not a member yet?&nbsp;
                <span className="active">Sign Up Now</span>{" "}
              </span>
            </Form>
          )}
        </Formik>
      </section>
    </main>
  );
}

要派遣的行动:

export const loginUser = createAsyncThunk(
  "auth/loginUser",
  async (credentials, thunkApi) => {
    try {
      const { data } = await API.post("auth/login", credentials)
      return data;
    } catch (err) {
      return thunkApi.rejectWithValue(err.message);
    }
  }
);

减速器:

import { createSlice } from "@reduxjs/toolkit";
import { loginUser } from "./auth.actions.js";

const authSlice = createSlice({
  name: "auth",
  initialState: {
    user: null,
    isAuthenticated: false,
    error: null,
  },
  reducers: {},
  extra减速器: (builder) => {
    builder
      .addCase(loginUser.pending, (state, action) => {
        state.user = null;
        state.isAuthenticated = false;
        state.error = null;
      })
      .addCase(loginUser.fulfilled, (state, action) => {
        state.user = action.payload;
        state.isAuthenticated = true;
        state.error = null;
      })
      .addCase(loginUser.rejected, (state, action) => {
        state.user = null;
        state.isAuthenticated = false;
        state.error = action.payload;
      });
  },
});
// Export reducer function by default
export default authSlice.reducer;

推荐答案

问题是,handleLogin从调用它的时候起就在所选的isAuthenticated值上有一个闭包,它在回调中永远不会是一个不同的或更新的值.

loginUser操作要么完成要么被拒绝.handleLogin回调可以await完成该操作.所有Redux—Toolkit都会解析,所以关键是首先打开解析的结果,看看它是被满足还是被拒绝.

详情请看Handling Thunk Results

const handleLogin = async (credentials) => {
  try {
    await dispatch(loginUser(credentials)).unwrap();

    // Success 😀, navigate home
    navigate("/");
  } catch(error) {
    // Failure 🙁, handle error
    // The error is the returned `thunkApi.rejectWithValue(err.message)` value
  }
};

Javascript相关问答推荐

React Native平面列表自动滚动

React存档iframe点击行为

类型脚本中只有字符串或数字键而不是符号键的对象

Angular:动画不启动

Msgraph用户邀请自定义邮箱模板

为什么我的列表直到下一次提交才更新值/onChange

使用Java脚本根据按下的按钮更改S文本

如果Arrow函数返回函数,而不是为useEffect返回NULL,则会出现错误

我可以使用空手道用户界面来获取网页的当前滚动位置吗?

如何将多维数组插入到另一个多维数组中?

本地库中的chartjs-4.4.2和chartjs-plugin-注解

在不删除代码的情况下禁用Java弹出功能WordPress

为什么当我更新数据库时,我的所有组件都重新呈现?

Google脚本数组映射函数横向输出

用另一个带有类名的div包装元素

表单数据中未定义的数组键

使用Perl Selify::Remote::Driver执行Java脚本时出错

如何将对象推送到firestore数组?

JSON Web令牌(JWT)错误:RSA密钥对的签名无效

如何在单击链接时设置一个JavaScript变量(以打开弹出窗口的特定部分)