Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

State Doesn't calculate the new value : (

I need help

I have a state depending on another state and want to update the second state based on the first state in the code below the setTotalPrice Doesn’t get the value of ingredientsPrice + pizzaPrice when I update the ingredientsPrice

import React, { useState } from "react";
import classes from "../../styles/Pages/Product.module.scss";
import Image from "next/image";
import axios from "axios";

function Product({ pizza }) {
    // The State of Pizza Size
    const [size, setSize] = useState(0);
    const [ingredientsPrice, setIngredientsPrice] = useState(0);
    const [pizzaPrice, setPizzaPrice] = useState(pizza.price[size]);
    const [totalPrice, setTotalPrice] = useState(pizza.price[size]);

    const handleIngredients = async (e, ingPrice) => {
        // add ingredients Price on every change and call total handler fn();
        if (e.target.checked) {
            setIngredientsPrice((prevIngPrice) => prevIngPrice + ingPrice);
            handleTotalPrice();
        } else {
            setIngredientsPrice((prevIngPrice) => prevIngPrice - ingPrice);
            handleTotalPrice();
        }
    };

    const handleTotalPrice = () => {
        // Calc the pizza price + ing price and update total
        setTotalPrice(pizzaPrice + ingredientsPrice);
    };

    return (
        <div className={classes.Container}>
            <div className={classes.Left}>
                <div className={classes.ImgContainer}>
                    <Image
                        alt={pizza.title}
                        src={pizza.image}
                        layout="fill"
                        objectFit="contain"
                    />
                </div>
            </div>
            <div className={classes.Right}>
                <h1 className={classes.Title}>{pizza.title}</h1>
                <span className={classes.Price}>${totalPrice}</span>
                <p className={classes.Description}>{pizza.description}</p>
                <h3 className={classes.Choose}>Choose Your Size</h3>
                <div className={classes.Sizes}>
                    <div
                        className={classes.SizeItem}
                        onClick={() => setSize(0)}
                    >
                        <Image
                            src={"/Images/size.png"}
                            alt="Small Size"
                            layout="fill"
                        />
                        <span className={classes.Size}>Small</span>
                    </div>
                    <div
                        className={classes.SizeItem}
                        onClick={() => setSize(1)}
                    >
                        <Image
                            src={"/Images/size.png"}
                            alt="Small Size"
                            layout="fill"
                        />
                        <span className={classes.Size}>Medium</span>
                    </div>
                    <div
                        className={classes.SizeItem}
                        onClick={() => setSize(2)}
                    >
                        <Image
                            src={"/Images/size.png"}
                            alt="Small Size"
                            layout="fill"
                        />
                        <span className={classes.Size}>Large</span>
                    </div>
                </div>
                <h3 className={classes.Choose}>
                    Choose Additional Ingredients
                </h3>
                <div className={classes.Ingredients}>
                    {pizza.extraOptions.map((cur, index) => {
                        const trimedName = cur.extra.trim();
                        const ingPrice = cur.price;

                        return (
                            <div
                                className={classes.IngredientOption}
                                key={"Extra" + index}
                            >
                                <input
                                    type={"checkbox"}
                                    name={trimedName}
                                    id={trimedName}
                                    className={classes.Checkbox}
                                    onChange={(e) =>
                                        handleIngredients(e, ingPrice)
                                    }
                                />
                                <label htmlFor={trimedName}>{cur.extra}</label>
                            </div>
                        );
                    })}
                </div>
                <div className={classes.Quentity}>
                    <input type={"number"} defaultValue={1} max={5} min={1} />
                    <button>Add to Cart</button>
                </div>
            </div>
        </div>
    );
}

export default Product;

export async function getServerSideProps({ params }) {
    const pizza = await axios.get(
        "http://localhost:3000/api/products/" + params.id
    );

    return {
        props: { pizza: pizza.data },
    };
}

I expect the totalPrice will update automatically when ingredientsPrice updates

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

The problem is with this:

setIngredientsPrice((prevIngPrice) => prevIngPrice - ingPrice);
handleTotalPrice();

setIngredientsPrice actually changes the ingredientsPrice in an async manner, so it is surely possible that the code inside handleTotalPrice execute when ingredientsPrice is not yet updated thus resulting with the wrong totalPrice value.

To overcome this common problem in React, you need to move your handleTotalPrice function call to a useEffect hook, like this:

    //update totalPrice when ingredientsPrice or pizzaPrice change
    useEffect(() => {
      setTotalPrice(ingredientsPrice + pizzaPrice);
      //or handleTotalPrice();
    },[ingredientsPrice, pizzaPrice]);

The function that we pass in useEffect hook will run whenever any of the variables listed inside dependency array (the array which we also pass into the useEffect) change.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading