skip to Main Content

I am trying to add id from redux to the previous data on paymentData state which then is inserted into paymentservice.create function. This function sends a post request to the backend

But I check the post request and I did not see the id but previous data are on the state.

I console.log the paymentdata state it does not contain the id until next render.

How do I push the data to the paymentdata state so that it will reflect immediately?

const ValidatePin = ({ setPaymentData, paymentData, setOpenValidatePinModal, showValidatePinModal, confirmLoading = '' }) => {
    const [form] = Form.useForm();
    const [errorMessage, setErrorMessage] = useState('');
    const [loading, setLoading] = useState(false);
    const [validationError, setValidationError] = useState([]);
    const { currentUser } = useSelector(state => state.user)
    const [paymentData, setPaymentData] = useState({});

    const handleCancelValidatePin = () => {
        setOpenValidatePinModal(false)
    }

    const onFinish = async (values) => {
        setLoading(true)
        setErrorMessage("")
        setValidationError("")
        try {
            var microtime = Date.now()
            console.log("microtime is ", microtime)
            const res = await UserServices.validatePin(values)
            if (res.data.msg == "success") {
                setLoading(false)
                // setOpenValidatePinModal(false)
                form.resetFields();
                setPaymentData(prevState => ({
                    ...prevState,
                    user_id: currentUser.id,

                }))
                console.log("##### data from payment ", paymentData)
                PaymentServices.create(paymentData)
            }


        } catch (error) {
            if (error) {
                setErrorMessage(error.response.data.data)
                if (error.response.data.errors) {
                    setValidationError(error.response.data.errors)
                }
            } else {
                setErrorMessage("Network Error. Try Again.")
            }

        } finally {
            setLoading(false)
            form.resetFields();
        }
    };
    console.log("payment data", paymentData)

    const handleOk = () => {
        setModalText('The modal will be closed after two seconds');
        setConfirmLoading(true);
        setTimeout(() => {
            setOpen(false);
            setConfirmLoading(false);
        }, 2000);
    };

    return (

        <div className='login'>

            <Modal
                title="Enter Pin"
                open={showValidatePinModal}
                confirmLoading={confirmLoading}
                footer={null}
            >
                {errorMessage && (<div className='alert alert-danger'>{errorMessage}</div>)}
                {loading && (<div className='alert alert-success'>Please Wait...</div>)}
                {ValidationError && Object.keys(validationError).map((error, index) => (
                    <ValidationError
                        message={validationError[error][0]}
                        key={index}
                    />
                ))}

                <Form
                    form={form}
                    onFinish={onFinish}
                    layout="vertical"
                >
                    <Form.Item label="Pin" required name="pin"
                        rules={[
                            {
                                required: true,
                                message: 'Pin is Required',
                            }]
                        }>
                        <Input placeholder="Enter Pin" />
                    </Form.Item>

                    <Button onClick={handleCancelValidatePin}>
                        Cancel
                    </Button>,
                    <Button type="primary" htmlType="submit" disabled={loading}>
                        Validate
                    </Button>,
                </Form>
            </Modal>
        </div >
    )
}

export default ValidatePin

2

Answers


  1. Reacts useState changes are async. All the state changes are executed at the end of the function. So when you update the state, its still not updated until the function ends.

    For example in this line setLoading(true). If you try logging console.log(loading), it will give false.

    If you want to have the data immediately then you can create the new state separately like this:

    if (res.data.msg == "success") {
        setLoading(false)
        // setOpenValidatePinModal(false)
        form.resetFields();
        const newState = {
            ...paymentData,
            user_id: currentUser.id,
        }
        setPaymentData(newState)
        console.log("##### data from payment ", newState)
        PaymentServices.create(newState)
    }
    
    Login or Signup to reply.
  2. In your code, you have two separate paymentData state variables: one passed as a prop and another defined locally in the component. To fix the issue and ensure that the paymentData state reflects immediately, you need to remove the locally defined paymentData state and use the prop paymentData directly.

    Here’s the updated code:

    const ValidatePin = ({ setPaymentData, paymentData, setOpenValidatePinModal, showValidatePinModal, confirmLoading = '' }) => {
        const [form] = Form.useForm();
        const [errorMessage, setErrorMessage] = useState('');
        const [loading, setLoading] = useState(false);
        const [validationError, setValidationError] = useState([]);
        const { currentUser } = useSelector(state => state.user);
    
        const handleCancelValidatePin = () => {
            setOpenValidatePinModal(false);
        };
    
        const onFinish = async (values) => {
            setLoading(true);
            setErrorMessage("");
            setValidationError([]);
            try {
                var microtime = Date.now();
                console.log("microtime is ", microtime);
                const res = await UserServices.validatePin(values);
                if (res.data.msg === "success") {
                    // Update the prop paymentData directly
                    setPaymentData(prevState => ({
                        ...prevState,
                        user_id: currentUser.id,
                    }));
                    console.log("##### data from payment ", paymentData);
                    PaymentServices.create(paymentData);
                }
            } catch (error) {
                if (error) {
                    setErrorMessage(error.response.data.data);
                    if (error.response.data.errors) {
                        setValidationError(error.response.data.errors);
                    }
                } else {
                    setErrorMessage("Network Error. Try Again.");
                }
            } finally {
                setLoading(false);
                form.resetFields();
            }
        };
    
        console.log("payment data", paymentData);
    
        return (
            <div className='login'>
                {/* Rest of the code */}
            </div>
        )
    };
    
    export default ValidatePin;
    

    With this change, the setPaymentData function passed as a prop will update the paymentData state immediately, and you can use it directly inside the onFinish function.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search