取消所有订阅和异步任务而不使用useEffect,必须在handleSubmit

时间:2020-09-18 18:02:26

标签: reactjs react-hooks

我遇到此错误,我已经通过各种互联网页面(包括stackoverflow)进行了不懈的搜索,找到了不同的解决方案,但找不到适合我的情况的

我将尽可能地总结一下,以免将话题扩展得太多而直截了当,我只是希望找到可以帮助我的人

我使用Stepper库对步骤进行排序

  • 在第1步中,我确认购买
  • 在第2步:在这种情况下,我只选择了付款方式
  • 在第3步中,我填写卡的详细信息以创建带有 名为Stripe的库,允许使用信用卡或借记卡付款
  • 在第4步:这是最后一步,仅当 付款已经完成

问题在于,在第3步中,使用从Stripe文档中提取的代码创建付款方式时,异步调用与await一起使用,这就是产生错误的原因,当我转到第4步时,我展示了一个新组件并且我消失了步骤3的组件,执行此操作时,我收到错误消息,我试图更新不再存在的组件中的状态,但是此刻我更新了步进器状态以将我带到最后一步,, II不进行任何状态更新,仍然收到消息,并看到导致此问题的原因是await调用,它要求我在移至新组件之前清理所有订阅和异步任务,所以我需要知道如何清理这个异步调用?

在第3步中应该说,验证卡数据表单的字段的整个过程以及开始创建付款方式时,都是在handleSubmit函数(由按钮调用)中完成的,这就是为什么使用useEffect的解决方案或异步调用不适用于我的情况,我需要一种直接在同一handleSubmit中清除所有内容的方法

我在这里留下我的摘要代码:

全局状态常量,在这里创建步进状态:

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
    }
};

现在这是步进器组件:

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);我转到步进器的最后一步,它将是最后一个组件,并且我消失了上一步中的Element组件和CheckoutForm2,这是我由于等待stripe.createPaymentMethod({...它说我正在尝试更新不再存在的组件中的状态,但是当发生setCurrentStep(3)时;我不再更新任何其他内容,而且我不明白为什么会收到错误,所以我认为该错误指的是await,并询问我还清理了异步await任务,但我不知道该怎么做,我必须通过同一ha​​ndleSubmit清理所有内容,而不必使用useEffect,因为这不适用于我的情况。

我最终会留下照片

enter image description here

0 个答案:

没有答案