0

I have add and subtract functions in my react container, that are passed whenever spans '+' or '-' are clicked, in order to calculate the total 'price' of three 'products' which are given different price values.

My problem is: when I first click either button, it console logs out the initial value 0 first, and then with every click afterwards, adds or subtracts from the total but always one step behind.

So, for example, if I click + for 'apples, price: 2', my console logs 0. Then, I'll click 'pears, price: 5', and my console will log 2, adding on the value from the previous click, instead of adding on 5 to the total.

Am I doing something wrong with my add and subtract functions? I change state.total before console logging it out, so why this happening?

here is my code:

class ProductList extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            total: 0
        }

        this.addFunction = this.addFunction.bind(this);
        this.subtractFunction = this.subtractFunction.bind(this);
    }

    addFunction(product) {
        var x = Number(product.price)
        this.setState({total: this.state.total + x});
        console.log('total is ' + this.state.total)
    }

    subtractFunction(product) {
        var x = Number(product.price)
        this.setState({total: this.state.total - x});
        console.log('total is ' + this.state.total)
    }

    render() {
        var createProducts = this.props.products.map((product, i) => {
            return <Product 
                    key={i} 
                    title={product.title} 
                    price={product.price}
                    addProductSetUp={() => this.addFunction(product)}
                    subtractProductSetUp={() => this.subtractFunction(product)}
                    />
        });

        return (
            <div>
                <ul>
                   {createProducts}
                </ul>
            </div>
        );
    }
}
user74843
  • 701
  • 2
  • 10
  • 28

2 Answers2

1

setState actions are asynchronous and are batched for performance gains. This is explained in documentation of setState:

https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

So in your example, the state has not yet been updated. You can use a callback to check on the state when it has been updated:

addFunction(product) {
    var x = Number(product.price)
    this.setState({total: this.state.total + x},
      () => console.log('total is ' + this.state.total));

}

but that's not necessarily useful in your case. You can simply print out the computed value

addFunction(product) {
    var x = Number(product.price);
    var total = this.state.total + x;
    this.setState({total});
    console.log('total is ' + total);
}
klugjo
  • 19,422
  • 8
  • 57
  • 75
1

ReactJS's setState is an asynchronous operation and that's why you don't have it's up-to-date value right away.

Should you need access right after, you can use:

this.setState(prevState => ({
  total: prevState.total + x,
}), () => {
  console.log(this.state)
})
Hemerson Carlin
  • 7,354
  • 1
  • 27
  • 38