-2

I am facing a issue which I am unable to solve. Whenever I am trying to add Coupon, it successfully returns the percentage from the database but as I have created a state which is holding the initial percentage which I have assigned by default 0. Whenever, I am clicking the button, it returns the value but the expected output comes after clicking the buttons second time. That means, the state is holding the initial value. Same goes for the later values as well. Whenever I give another value and click the button that state is holding the previous value and I have to click the button second time to assign the new value.

 const [coupons, setCoupon] = useState({
        code: '',
        percentage: ''
    });
    const handleChange = e => {
        setCoupon({
            ...coupons,
            [e.target.name]: e.target.value
        })
    }
    const handleSubmit = e => {
        const data = {
            code: code
        }

        redeemCoupon(token, data)
            .then(response => {
                setCoupon({
                    ...coupons,
                    code: "",
                    percentage: response.data[0].percentage,
                })
                const discountAmount = getOrderTotal() * percentage;
                console.log(discountAmount);
            })
            .catch(err => { console.log(err) })
    }

Output:

0 Checkout.js:85 1228.39 Checkout.js:85 1228.39 Checkout.js:85 1719.746

I have tried to use multiple solutions. My Expected output would be like this:

1228.39 Checkout.js:85 1719.746 Checkout.js:85

Whenever I will click on the button, It will change the state value to the data returned from the server and do the rest of the thing. But in this case, it is working one step ahead.

  • Do you specifically mean that `discountAmount` doesn't contain the value you expect? We can't see what `getOrderTotal()` does, or where you defined `percentage` in that scope. Though from the description it sounds likely that you're experiencing [this](https://stackoverflow.com/q/54069253/328193). – David Nov 28 '22 at 19:28
  • Yes, the discountAmount is not working as I expected. Initially the percentage is " ". Whenever I add a promo code & enter the apply button it should multiply the percentage returned from the server with the amount from getOrderTotal. But it returns 0. On the second click of the apply button, it gives the expected output. Again if I give a different percentage, it returns the value from the second click. But In 4th click, it gives the value which was expected on the 3rd time. So, it is working 1 step behind. I think I made you understand. – Sifat Hasan Wakib Nov 28 '22 at 19:50
  • Does this answer your question? [The useState set method is not reflecting a change immediately](https://stackoverflow.com/questions/54069253/the-usestate-set-method-is-not-reflecting-a-change-immediately) – David Nov 28 '22 at 19:51

1 Answers1

0

So the discount amount is going to be calculated from the mystery function and then from what I presume is the destructured state value, percentage. The problem you are likely having is that percentage doesn't update immediately in the closure formed from your response callback. As a matter of fact, the value doesn't change until the component re-renders. The value for percentage from state will be the value used to render the component and will remain so until the end of your callback function completes, the component re-renders and a new callback function with the new closure values will be created. There is a great blog about this that changed how I think of hooks and functional components. If you want to read more, Dan Abramov's blog: https://overreacted.io/a-complete-guide-to-useeffect/ is absolutely perfect in explaining what is going on here.

To fix your issue, use the percentage from your response object to perform your calculation not the one in the closure which assumes getOrderTotal() doesn't depend on anything in state that changed.

const discountAmount = getOrderTotal() * response.data[0].percentage;

Alternatively, think of discountAmount in terms of declarative values. Let it be the result of the aforementioned calculation, but put it in the body of your component not in your callback and let the re-render drive the result.

CodeoftheWarrior
  • 311
  • 2
  • 12