使用axios和formik进行登录身份验证

时间:2020-07-29 00:54:46

标签: reactjs authentication axios formik

我是同时使用axios和formik的新手,可能在这里犯了一个简单的错误。我正在尝试检查用户的电子邮件和密码是否存在以及是否已正确键入。进行身份验证后,应使用useContext登录,然后将其重定向到首页。

当前,提交后,表单仅保持灰色,而未到达.then / .catch块。我键入auth参数的方式是否有问题?

URLSession.shared.dataTaskPublisher(for: URLRequest(url: url))
   // #1 URLRequest fails, throw APIError.network
   .mapError { 
       APIError.network(code: $0.code.rawValue, description: $0.localizedDescription) 
   }
   .flatMap { v in
      Just(v)

         // #2 try to decode data as a `Response`
         .decode(type: Response.self, decoder: JSONDecoder())

         // #3 if decoding fails,
         .tryCatch { _ in
            Just(v)
               // #3.1 ... decode as an `ErrorResponse`
               .decode(type: ErrorResponse.self, decoder: JSONDecoder())
               
               // #4 if both fail, throw APIError.decoding
               .mapError { _ in APIError.decoding(description: "error decoding") }

               // #3.2 ... and throw `APIError.api
               .tryMap { throw APIError.api(description: $0.errorMessage) }
         }

         // force unwrap is not terrible here, since you know 
         // that `tryCatch` only ever throws APIError
         .mapError { $0 as! APIError }
   }

后端的Node JS API:

const LoginForm = () => {
  const authenticate = useContext(AuthContext);
  const [serverState, setServerState] = useState();
  const handleServerResponse = (ok, msg) => {
    setServerState({ok, msg});
  };
  const handleOnSubmit = (values, actions) => {
    axios({
      method: "POST",
      url: "http://localhost:5000/api/users/login",
      data: values,
      auth: {
        email,
        password
      }
    })
    .then(response => {
      actions.setSubmitting(false);
      actions.resetForm();
      handleServerResponse(true, "Logged In!");
    })
    .catch(error => {
      actions.setSubmitting(false);
      handleServerResponse(false, error.response.data.error);
    });
    authenticate.login();
    Router.push("/")
  };

  return (
    <Formik
      initialValues={{
        email: "",
        password: "",
      }}
      validationSchema={Yup.object().shape({
        email: Yup.string(),
        password: Yup.string(),
      })}
      onSubmit={handleOnSubmit}
    >
      {({ isSubmitting }) => (
      <Form>
        <Field
          name="email"
          type="email"
          fullWidth
          component={TextField}
          variant="outlined"
          label="Email"
        />
        <Box pt={1}>
        <Field
          name="password"
          type="password"
          fullWidth
          component={TextField}
          variant="outlined"
          label="Password"
        />
        </Box>
        <Box pt={2}>
          <Button
            type="submit"
            variant="contained"
            fullWidth
            color="primary"
            disabled={isSubmitting}
          >
            Submit
          </Button>
          {serverState && (
          <Typography className={!serverState.ok ? "errorMsg" : ""}>
            {serverState.msg}
          </Typography>
        )}
        </Box>
      </Form>
      )}
    </Formik>
  );
};

1 个答案:

答案 0 :(得分:0)

该表单显示为灰色的原因是因为您使用isSubmitting,并且在提交表单时将其设置为true,但是在handleOnSubmit内部,您具有同步功能,因此只有在表格已经认为您完成了actions.setSubmitting(false)后,您才致电onSubmit

执行此操作的另一种方法是使handleOnSubmit返回一个诺言,一旦诺言得到解决,formik将自动将isSubmitting设置为false

这在the docs

中有解释

重要:如果onSubmitasync,则Formik解决后,将自动代表您将isSubmitting设置为false。这意味着您不需要手动调用formikBag.setSubmitting(false)。但是,如果您的onSubmit函数是同步的,则您需要自己调用setSubmitting(false)

所以我建议您做并解决您的问题,是将handleOnSubmit设为async方法并返回axios调用(返回承诺)或使用await

例如

const handleOnSubmit = (values, actions) => {
  // returning a promise
  return axios({
    method: "POST",
    url: "http://localhost:5000/api/users/login",
    data: values,
    auth: {
      email,
      password
    }
  })
  .then(response => {
    actions.setSubmitting(false);
    actions.resetForm();
    handleServerResponse(true, "Logged In!");
  })
  .catch(error => {
    actions.setSubmitting(false);
    handleServerResponse(false, error.response.data.error);
  });

  // this shouldn't be outside the .then/.catch
  // if you are going to use .then/.catch, put the above line inside it
  // authenticate.login();
  // Router.push("/")
};

或使用async / await

//               using async
const handleOnSubmit = async (values, actions) => {

  //           using await in the axios call
  try {
    const response = await axios({
      method: "POST",
      url: "http://localhost:5000/api/users/login",
      data: values,
      auth: {
        email,
        password
      }
    })
    actions.setSubmitting(false);
    actions.resetForm();
    handleServerResponse(true, "Logged In!");
  } catch(error) {
    actions.setSubmitting(false);
    handleServerResponse(false, error.response.data.error);
  }
  authenticate.login();
  Router.push("/")
};