skip to Main Content

The onSubmit callback paymentHandler is supposed to run as soon as the form is submitted, I didn’t specify button type. but as soon as I click submit button, nothing happens until I click the submit button again. The button and form inputs are styled components. They work fine in other pages.


  const callPaystack = () => {
    fetch('https://api.paystack.co/transaction/initialize', {
     method: 'POST',
     headers: {
       'Authorization': `Bearer ${import.meta.env.VITE_PAYSTACK_SECRET_KEY}`,
       'Content-Type': 'application/json',
     },
     body: JSON.stringify({
       email: buyerEmail, 
       amount: totalPrice * 100,
       channels: ["card", "bank", "qr", "ussd"],
       metadata: {
         "cancel_action": "https://crown-storex.netlify.app",
       }
     }),
    }).then((res) => res.json())
    .then((data) => {
      setPaymentResult(data);
      console.log(paymentResult)
    })
  }

  const paymentHandler = async (e) => {
    e.preventDefault();
    await callPaystack();
    location.href = paymentResult.data.authorization_url;
  
  }

      <form onSubmit={paymentHandler}>
        <FormInput
          label="Email"
          name="email"
          type="email"
          value={buyerEmail}
          onChange={(e) => setBuyerData({ ...buyerData, buyerEmail: e.target.value })}
          required
        />
        <Button  buttonType={buyerEmail ? "inverted" : "disabled"} >Pay Now With Paystack</Button>
      </form>


2

Answers


  1. This should be happening because you are updating the state which updates after paymenthandler is completed entirely.

    You should return the value from paymenthandler and use to set location.href

    const paymentHandler = async (e) => {
        e.preventDefault();
       let val = await callPaystack();
        location.href = val.data.authorization_url;
      
      }
    
    
    Login or Signup to reply.
  2. You are not returning the result from the fetch your async function. To give a simplified example, what you do is similar like this:

    const foo = async function () {
      fetch('https://jsonplaceholder.typicode.com/todos/1')
        .then(response => response.json()).then(json => console.log(json));
    }
    
    const paymentHandler = async () => {
      await foo();
      console.log('this should be at the end, right?');
    }
    
    paymentHandler();

    What you should be doing is something like this:

    const foo = async function () {
      return fetch('https://jsonplaceholder.typicode.com/todos/1')
          .then(response => response.json())
    }
    
    const paymentHandler = async () => {
      const result = await foo();
      console.log(result);
      console.log('this should be at the end, right?');
    }
    
    paymentHandler();

    So what happens in the second example, is you return the promise from the fetch function, inside the first example you return a promise (async function always return promise) that is not part of your fetch function, and therefore resolves immediately. So my advice is: return the result from fetch and then change the URL.

    NB: One more thing you might try if you don’t want to rewrite your function is use a useEffect hook that is part of React, and set paymentResult as a depencency. This means whenever paymentResult changes this function runs. Something like this:

    useEffect(() => {
      if (paymentResult.status === 'success') {
        location.href = paymentResult.data.authorization_url;
      }
    }, [paymentResult])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search