State 不计算新值:(

发布于 2025-01-16 04:49:53 字数 5493 浏览 0 评论 0原文

我需要帮助

我的状态依赖于另一个状态,并且想要根据 setTotalPrice 下面的代码中的第一个状态更新第二个状态 未获取 ingredientsPrice + PizzaPrice< 的值/code> 当我更新 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 },
    };
}

我希望 totalPrice 会在 ingredientsPrice 更新时自动更新

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

ゝ偶尔ゞ 2025-01-23 04:49:53

问题在于:

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

setIngredientsPrice实际上以异步方式更改了ingredientsPrice,因此handleTotalPrice中的代码肯定有可能在<时执行code>ingredientsPrice 尚未更新,因此导致 totalPrice 值错误。

为了克服 React 中的这个常见问题,您需要将 handleTotalPrice 函数调用移动到 useEffect 挂钩,如下所示:

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

我们传入 useEffect 的函数每当依赖项数组(我们也传递到 useEffect 的数组)中列出的任何变量发生更改时,code> 钩子就会运行。

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.

街道布景 2025-01-23 04:49:53

React 中的状态更新是异步的,这意味着它们不会立即应用,而是排队。

我建议您将依赖状态放入一个对象中,然后更新该对象。 ingredientsPricetotalPrice 是相关的。如果更新其中一个,则还需要更新另一个(至少根据我的理解),因此将它们放在一个对象状态中并仅更新该状态。

请注意,更新状态时必须提供新对象,因为仅执行不深度比较。

看看这篇博客文章了解更多详情。

State updates in React are asynchronous, that means they are not applied immediately but queued.

I would suggest that you put dependent state in one single object which you then update. ingredientsPrice and totalPrice are dependent. If you update one, you need to update the other as well (at least from my understanding), so put them together in an object state and update just that one state.

Be aware that you must provide a new object when you update state as only a no deep comparism is performed.

Have a look at this blog post for more details.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文