reactjs - 取消所有订阅和不使用useEffect的异步任务,必须在handleSubmit
问题描述
我有这个错误,我已经通过包括stackoverflow在内的各种互联网页面不知疲倦地搜索不同的解决方案,但我找不到适用于我的案例的解决方案,
我会尽可能的总结,以免话题扩展太多,直奔主题,只希望能找到能帮助我的人
我使用 Stepper 库对步骤进行排序
- 在第1步:确认购买
- 在第 2 步中:我在这种情况下选择付款方式仅限卡
- 在第 3 步中:我填写卡详细信息以使用名为 Stripe 的库创建付款,该库允许使用信用卡或借记卡付款
- 在第 4 步:这是最后一步,只有在付款完成后才会显示
问题是,在步骤 3 中使用从 Stripe 文档中提取的代码创建付款方式,异步调用与 await 一起使用,这是产生错误的原因,当我转到步骤 4 时,我显示了一个新组件,然后我消失了步骤 3 的组件,当我这样做时,我收到错误消息,我正在尝试更新不再存在的组件中的状态,但是此刻我更新我的 Stepper 状态以将我带到最后一步,II不要再做任何状态更新,我仍然收到消息并看到导致此问题的是等待调用,它要求我在移动到新组件之前清理所有订阅和异步任务,所以我需要知道如何清理这个异步调用?
在第3步应该说验证卡数据表单的字段以及开始创建支付方式的整个过程是在一个按钮调用的handleSubmit函数中完成的,,这就是为什么解决方案或使用 useEffect 的异步调用不适用于我的情况,我需要一种方法来直接在同一个 handleSubmit 中清理所有内容
在这里我留下我的总结代码:
全局状态常量,在这里我创建了我的 Stepper 状态:
here delete code of several state variables, just leave the state variables of the stepper when state change updating on a number
const useStateGlobal = () => {
const [steps] = useState(
[{
title: 'Confirmar Compra',
href: 'http://example1.com',
onClick: (e) => {
e.preventDefault()
console.log('onClick', 1)
}
}, {
title: 'Seleccionar tipo de pago',
href: 'http://example2.com',
onClick: (e) => {
e.preventDefault()
console.log('onClick', 2)
}
}, {
title: 'Detalles de pago',
href: 'http://example3.com',
onClick: (e) => {
e.preventDefault()
console.log('onClick', 3)
}
}, {
title: 'Compra Finalizada',
href: 'http://example4.com',
onClick: (e) => {
e.preventDefault()
console.log('onClick', 4)
}
}]
);
const [currentStep, setCurrentStep] = useState(0);
return {
steps,
currentStep,setCurrentStep
}
};
现在这是 Stepper 组件:
export const Confirmar_Paquete_Stepper = () => {
const { steps, currentStep, setCurrentStep } = useBetween(useStateGlobal);
const buttonStyle = { background: '#E0E0E0', width: 200, padding: 16, textAlign: 'center',
margin: '0 auto', marginTop: 32 };
const onClickNext = (e) => {
let valor = (currentStep == null || currentStep == 0 ) ? 1 : currentStep+1;
setCurrentStep(valor);
}
const onClickBack = (e) => {
let valor = (currentStep == null || currentStep == 0) ? 1 : currentStep - 1;
setCurrentStep(valor);
}
if (currentStep == 0) {
return (
<div id="contenedor-stepper-compra-paquete">
<Stepper steps={steps} activeStep={currentStep} />
<Confirmar_Paquete />
</div>
);
}
else if (currentStep == 1) {
return (
<div id="contenedor-stepper-compra-paquete">
<Stepper steps={steps} activeStep={currentStep} />
<Seleccionar_Tipo_Pago_Paquete />
<div style={buttonStyle} onClick={onClickBack}>Volver</div>
</div>
);
} else if (currentStep == 2) {
return (
<div id="contenedor-stepper-compra-paquete">
<Stepper steps={steps} activeStep={currentStep} />
these are the components that create the inputs of the card number, expiration
date, cvc and process and create the card payment method with the Stripe library
<Elements stripe={stripePromise}>
<CheckoutForm2/>
</Elements>
<div style={buttonStyle} onClick={onClickBack}>Volver</div>
</div>
);
}
else if (currentStep == 3) {
return (
<div id="contenedor-stepper-compra-paquete">
<Stepper steps={steps} activeStep={currentStep} />
<Finalizar_Compra_Paquete />
<div style={buttonStyle} onClick={onClickBack}>Volver</div>
</div>
);
}
};
现在是 CheckoutForm2 组件
const CheckoutForm2 = () => {
const { steps, currentStep, setCurrentStep, token, datos_paquete_seleccionado, setDatos_paquete_seleccionado, camposDatosTarjeta, setcamposDatosTarjeta, formErrors, setformErrors, errores_servTarjeta, seterrores_servTarjeta,
paseValidacionFormTitularTarjeta, setpaseValidacionFormTitularTarjeta,
paseValidacionFormCorreoTarjeta, setpaseValidacionFormCorreoTarjeta,
paseValidacionFormTarjeta, setpaseValidacionFormTarjeta,
paseValidacionFormFechaExpTarjeta, setpaseValidacionFormFechaExpTarjeta,
paseValidacionFormCvcTarjeta, setpaseValidacionFormCvcTarjeta,
paseValidacionFormCiudadTarjeta, setpaseValidacionFormCiudadTarjeta,
paseValidacionFormCodigoPostalTarjeta, setpaseValidacionFormCodigoPostalTarjeta
} = useBetween(useStateGlobal);
const stripe = useStripe();
const elements = useElements();
const titularTarjetaRegex = RegExp(
/^[A-Za-z\s]+$/
);
const emailRegex = RegExp(
/^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
);
const codigopostalTarjetaRegex = RegExp(
/^[0-9]+$/
);
const ciudadTarjetaRegex = RegExp(
/^[A-Za-z]+$/
);
useEffect(() => {
return () => {
};
}, []);
const HandleValidar = async (event) => {
Here I have code only to validate the form fields by OnChange, I have deleted it because they
are not important
}
const handleSubmit = async (event) => {
event.preventDefault();
const { titular_tarjeta, correo_tarjeta, ciudad_tarjeta, codigo_postal_tarjeta } = event.target;
Here I leave only an example of how valid each field of my form when I click directly on handleSubmit by onClick,
//TITULAR TARJETA
if (titular_tarjeta.value.length < 3) {
setformErrors(prevState => ({ ...prevState, titular_tarjeta: "Ingrese mínimo 3 caracteres"
}));
seterrores_servTarjeta(prevState => ({ ...prevState, titular_tarjeta: "" }));
setpaseValidacionFormTitularTarjeta("NO");
}
else if (!titularTarjetaRegex.test(titular_tarjeta.value)) {
setformErrors(prevState => ({ ...prevState, titular_tarjeta: "Formato de nombres inválido"
}));
seterrores_servTarjeta(prevState => ({ ...prevState, titular_tarjeta: "" }));
setpaseValidacionFormTitularTarjeta("NO");
}
else if (titular_tarjeta.value.length > 22) {
setformErrors(prevState => ({ ...prevState, titular_tarjeta: "Ingrese maximo 22 caracteres"
}));
seterrores_servTarjeta(prevState => ({ ...prevState, titular_tarjeta: "" }));
setpaseValidacionFormTitularTarjeta("NO");
}
else {
setformErrors(prevState => ({ ...prevState, titular_tarjeta: "" }));
seterrores_servTarjeta(prevState => ({ ...prevState, titular_tarjeta: "" }));
setpaseValidacionFormTitularTarjeta("SI");
}
if (!stripe || !elements) {
// Stripe.js has not yet loaded.
// Make sure to disable form submission until Stripe.js has loaded.
return;
}
Here I validate through a set of each state that all the fields have been completed and validated
correctly to just start creating the payment
if (paseValidacionFormTitularTarjeta == "SI" && paseValidacionFormCorreoTarjeta == "SI" && paseValidacionFormTarjeta == "SI" && paseValidacionFormFechaExpTarjeta == "SI" && paseValidacionFormCvcTarjeta == "SI" && paseValidacionFormCiudadTarjeta == "SI" && paseValidacionFormCodigoPostalTarjeta == "SI")
{
const cardElement = elements.getElement(CardNumberElement);
const { error, paymentMethod } = await stripe.createPaymentMethod({
type: 'card',
card: cardElement,
billing_details: {
email: camposDatosTarjeta.correo_tarjeta,
name: camposDatosTarjeta.titular_tarjeta,
address: {
city: camposDatosTarjeta.ciudad_tarjeta,
country: 'PE',
postal_code: camposDatosTarjeta.codigo_postal_tarjeta,
}
},
});
if (error) {
}
else
{
This is where the moment I update the Stepper to number 3, which would be the last step ,, is when the error appears ,,,
the one that causes this error is the await ,,, since if I delete all that code above the await stripe the error does not appear anymore ,,, then I want to know how to clean the asynchronous tasks before moving to a new component, everything must be performed in my function by handlesubmit
setCurrentStep(3);
}
}
};
return (
<div id="contenedor-detalles-tarjeta">
<Container component="main" maxWidth="md" justify="center">
<label className="detalles-tarjeta-titulo">
<Typography >
<span >Detalles de tarjeta</span>
</Typography>
</label>
<form id="realizar-pago-visa" onSubmit={handleSubmit} noValidate>
Here I have deleted all the code of the creation of the fields of the payment form, I have
only left the handleSubmit button
<Button type="submit" className="confirmar-orden" name="confirmar_orden" disabled=
{!stripe} variant="contained" color="primary">Confirmar orden</Button>
</form>
</Container>
</div>
);
}
- 0 是第 1 步
- 1是步骤2
- 2是步骤3
- 3是第4步
如您所见,使用 setCurrentStep (3); 我转到 Stepper 的最后一步,这将是最后一个组件,我消失了上一步中的 Element 组件和 CheckoutForm2,这就是我收到错误的地方,因为 await stripe.createPaymentMethod ({...它说我正在尝试更新不再存在的组件中的状态,但是当 setCurrentStep (3) 发生时;我不再更新任何其他内容,我不明白为什么会收到错误,所以我认为错误指等待并要求我也清理异步等待任务,但我不知道该怎么做,我必须通过相同的句柄提交清理所有内容,而不使用 useEffect,因为对于我的情况不适用。
最后我会留下一张照片
解决方案
推荐阅读
- memory - 如何从 erlang 崩溃转储中找到内存泄漏进程?
- php - 有人可以向我解释 PHP SQL Select 数据吗?
- android - 布局预览在 android studio 3.4.1 中不起作用
- laravel - Laravel:$errors->first() 不显示错误。如何让它发挥作用?
- automation - 正则表达式 (0+1)*1(0+1)*0 DFA
- css - 如何将 CSS 类添加到 Flask-Table 列
- xml - 增量元素名称的 xml 架构列表
- android - 如何在运行时在 mapbox 中添加具有不同图像的标记?
- google-analytics - 属性设置未在 Google Analytics 中加载
- java - Spring中“排序超出内存限制”MongoDb的问题