我是同时使用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>
);
};
答案 0 :(得分:0)
该表单显示为灰色的原因是因为您使用isSubmitting
,并且在提交表单时将其设置为true
,但是在handleOnSubmit
内部,您具有同步功能,因此只有在表格已经认为您完成了actions.setSubmitting(false)
后,您才致电onSubmit
。
执行此操作的另一种方法是使handleOnSubmit
返回一个诺言,一旦诺言得到解决,formik将自动将isSubmitting
设置为false
。
这在the docs
中有解释重要:如果
onSubmit
为async
,则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("/")
};