使用带有异步函数的history.block/回调/异步/等待 [英] Using history.block with asynchronous functions/callback/async/await
本文介绍了使用带有异步函数的history.block/回调/异步/等待的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我在路线中有一个表单,如果有任何验证错误,它应该不允许用户导航到另一个路线。如果没有验证错误,则允许导航到其他路线。
下面是我当前的代码,onBlock
函数不起作用,因为提交然后验证表单的函数是异步的。
FormComponent.js
import React, { useState, useEffect, useRef } from "react";
import { FieldArray } from "formik";
import { useHistory } from "react-router-dom";
import * as Yup from "yup";
import Form from "./Form";
import TextInput from "./TextInput";
const FormComponent = () => {
const history = useHistory();
const [initialValues, setInitialValues] = useState();
const [isSubmitted, setIsSubmitted] = useState(false);
const block = useRef();
const formRef = useRef(null);
const onFormSubmit = async (values) => {
setIsSubmitted(true);
};
const validationSchema = () => {
const schema = {
test: Yup.string().required("Input is Required")
};
return Yup.object(schema);
};
const onBlock = () => {
const { submitForm, validateForm } = formRef?.current || {};
// submit form first
submitForm()
.then(() => {
// then validate form
validateForm()
.then(() => {
// if form is valid - should navigate to route
// if form is not valid - should remain on current route
return formRef?.current.isValid;
})
.catch(() => false);
})
.catch(() => false);
};
const redirectToPage = () => {
history.push("/other-page");
};
useEffect(() => {
block.current = history.block(onBlock);
return () => {
block.current && block.current();
};
});
useEffect(() => {
if (isSubmitted) redirectToPage();
}, [isSubmitted]);
useEffect(() => {
setInitialValues({
test: ""
});
}, []);
return initialValues ? (
<Form
initialValues={initialValues}
onSubmit={onFormSubmit}
formRef={formRef}
validationSchema={validationSchema}
>
<FieldArray
name="formDetails"
render={(arrayHelpers) =>
arrayHelpers && arrayHelpers.form && arrayHelpers.form.values
? (() => {
const { form } = arrayHelpers;
formRef.current = form;
return (
<>
<TextInput name="test" />
<button type="submit">Submit</button>
</>
);
})()
: null
}
/>
</Form>
) : null;
};
export default FormComponent;
如果用户尝试提交输入中没有任何值的表单,我预计onBlock
将返回false
以阻止导航。但这似乎并不奏效。不过,只需在onBlock
函数中返回false
就可以了。因此,history.block
函数似乎不接受任何回调。我还尝试将其转换为async
函数和await
submitForm
&;validateForm
函数,但仍然没有效果。有什么办法可以绕过这件事吗?如有任何帮助,将不胜感激。
以下是CodeSandbox的示例。
推荐答案
history.block
函数接受提示回调,您可以使用该回调来提示用户或执行其他操作以响应页面被阻止。若要阻止该页面,您只需呼叫history.block()
详细信息here。
onSubmit
回调。因此,如果您想要在存在验证错误时阻止页面,您可以使用formik上下文订阅验证isValid
,并且只要是假阻止。
const useIsValidBlockedPage = () => {
const history = useHistory();
const { isValid } = useFormikContext();
useEffect(() => {
const unblock = history.block(({ pathname }) => {
// if is valid we can allow the navigation
if (isValid) {
// we can now unblock
unblock();
// proceed with the blocked navigation
history.push(pathname);
}
// prevent navigation
return false;
});
// just in case theres an unmount we can unblock if it exists
return unblock;
}, [isValid, history]);
};
这里有一个codesandbox,是从你的改编而来的。我删除了一些不需要的组件。
另一个解决方案是手动验证所有页面转换,并选择自己何时允许转换,在这种情况下,如果validateForm
不返回错误,则允许转换。
// blocks page transitions if the form is not valid
const useFormBlockedPage = () => {
const history = useHistory();
const { validateForm } = useFormikContext();
useEffect(() => {
const unblock = history.block(({ pathname }) => {
// check if the form is valid
validateForm().then((errors) => {
// if there are no errors this form is valid
if (Object.keys(errors).length === 0) {
// Unblock the navigation.
unblock();
// retry the pagination
history.push(pathname);
}
});
// prevent navigation
return false;
});
return unblock;
}, [history, validateForm]);
};
和codesandbox此处
这篇关于使用带有异步函数的history.block/回调/异步/等待的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文