componentDidMount updating synchronously

问题: I'm loading data from saved session using: componentDidMount() { if (JSON.parse(localStorage.getItem('savedData')) !== null) { this.setState({ car...

问题:

I'm loading data from saved session using:

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

cartItems is an array of objects. Which seems is updated before

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

functions are called, for example this.getPriceOnLoad function:

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;
}

but, in getPriceOnLoad function, this.state.cartItems.length is equal to 0, so for loop is not executing. I can see in React dev tools that this array has some length. Is it because componentDidMount() is executing state change synchronously and can't see updated array immediately? So my question is how could i update price and quantity of items after array is initialized?


回答1:

Your state is not updated in order. For this, you could store the cartItems in a temporary value, and send it to each functions :

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),
        });
    }
}

You could also make your function significantly shorter by using reduce:

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

Can you show us your second function too ? It may be optimized as well. Done.


回答2:

the wrong thing that you are doing is trying to use values from the state on your functions that will define your state.

you have 2 approaches to solve this:

1) use the callback function from setState and then set the state again with the new data (which into my opinion is not the best approach)

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) send the values to your functions

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

回答3:

getPriceOnLoad() is executed before this.setState is executed. So you cannot refer to this.state in getPriceOnLoad().

When you call this.setState({}), JS first needs to generate the object for the setState() function. Means the functions you are referring to run first, then this.setState().

And in any case this.setState() is an asynchronous function, so this.state is not directly available after setState() execution.

  • 发表于 2019-01-22 20:57
  • 阅读 ( 227 )
  • 分类:网络文章

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除