componentDidMount同步更新

时间:2019-01-21 15:05:40

标签: javascript reactjs

我正在使用以下方法从保存的会话中加载数据:

componentDidMount() {
    if (JSON.parse(localStorage.getItem('savedData')) !== null) {
        this.setState({
            cartItems: JSON.parse(localStorage.getItem('savedData')),
            totalPrice: this.getPriceOnLoad(),
            totalItems: this.getItemsOnLoad(),
        });
    }
}

cartItems是一个对象数组。似乎是之前更新的

this.getPriceOnLoad();
this.getItemsOnLoad();

函数被调用,例如this.getPriceOnLoad函数:

getPriceOnLoad() {
    let itemsPrice = 0;
    for (let i = 0; i <= this.state.cartItems.length - 1; i++) {
        itemsPrice += this.state.cartItems[i].quantity * this.state.cartItems[i].price;
    }
    return itemsPrice;
}

但是,在getPriceOnLoad函数中,this.state.cartItems.length等于0,因此不会执行for循环。我可以在React开发工具中看到此数组有一定长度。是否因为componentDidMount()正在同步执行状态更改而无法立即看到更新的数组?所以我的问题是数组初始化后如何更新商品的价格和数量?

3 个答案:

答案 0 :(得分:4)

您的状态未按顺序更新。为此,您可以将cartItems存储在一个临时值中,并将其发送给每个函数:

componentDidMount() {
    if (JSON.parse(localStorage.getItem('savedData')) !== null) {
        const cartItems = JSON.parse(localStorage.getItem('savedData'))
        this.setState({
            cartItems, //Short syntax for 'cartItems: cartItems'
            totalPrice: this.getPriceOnLoad(cartItems),
            totalItems: this.getItemsOnLoad(cartItems),
        });
    }
}

您还可以通过使用reduce使功能大大缩短:

this.setState({
    cartItems,
    totalPrice: cartItems.reduce((total, item) => total + (item.quantity * item.price), 0),
    totalItems: cartItems.reduce((total, item) => total + item.quantity, 0),
});

您也可以向我们展示您的第二个功能吗?可能也会对其进行优化。完成。

答案 1 :(得分:2)

您做的错误的事情是尝试在函数中使用状态值来定义状态。

您有2种解决方法:

1)使用<html> <head> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <link href="~/lib/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" /> <script src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script> <style> #chart_container{ width:400px; height:400px; border: 1px solid #ddd; padding:1px; border-radius:4px; } </style> </head> <body> <div id="chart_container"> <canvas id="bar_chart"></canvas> </div> <script> var purchaseOrderID = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.PurchaseOrderID)); var qtyOrdered = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.QtyOrdered)); @*@{ var purchaseOrderID = ViewBag.PurchaseOrderID;} @{ var qtyOrdered = ViewBag.QtyOrdered;}*@ var ctx = $('#bar_chart'); var barchart = new Chart(ctx, { type: 'bar', data: { labels: purchaseOrderID, dataset: [{ label: "Bar Chart example", data:qtyOrdered, backgroundColor: ["rgba(244,166,54,0.5)", "rgba(145,65,72,0.5)", "(74,25,92,0.5)"], borderColor: ["rgba(244,166,54,0.5)", "rgba(145,65,72,0.5)", "(74,25,92)"], borderwidth: 1 }] }, options: { maintainAspectRatio: false, scales: { xAxes: [{ ticks: { beginAtZero: true } }] }, legend: { display: false } }, }); </script> </body> </html> 中的回调函数,然后使用新数据再次设置状态(我认为这不是最佳方法)

setState

2)将值发送到您的函数

componentDidMount() {
    if (JSON.parse(localStorage.getItem('savedData')) !== null) {
        const cartItems = JSON.parse(localStorage.getItem('savedData'))
        this.setState({
            cartItems
        }, ()=> {
           this.setState({
            totalPrice: this.getPriceOnLoad(cartItems),
            totalItems: this.getItemsOnLoad(cartItems),
           });
        })
    }
}

答案 2 :(得分:0)

getPriceOnLoad()在执行this.setState之前执行。因此,您无法在this.state中引用getPriceOnLoad()

调用this.setState({})时,JS首先需要为setState()函数生成对象。表示您要引用的功能先运行,然后运行this.setState()

在任何情况下,this.setState()是一个异步函数,因此this.state在执行setState()之后不能直接使用。