На самом деле проблема в том, что вы вызываете метод sum сразу после setState, а setState асинхронный, поэтому при выполнении суммы состояние не изменяется, setState получает второй параметр, обратный вызов, который будет выполнен после состояния.обновлен, см. документ ниже https://reactjs.org/docs/react-component.html#setstate
Работа с sumTotalAmount на основе prevState решает проблему
sumTotalAmount() {
this.setState( (prevState, props) => { return { totalAmount : prevState.cart.map(( product ) => {
return Number(product.quantity) * Number(product.price);
} ).reduce( ( total, current ) => total += current )}
})
}
const products = [
{
id: "1",
title: "item 1",
price: "2450",
left: "14",
quantity: "1"
},
{
id: "2",
title: "item 2",
price: "2450",
left: "178",
quantity: "1"
},
{
id: "3",
title: "item 3",
price: "2450",
left: "1",
quantity: "1"
},
{
id: "4",
title: "item 4",
price: "2450",
left: "12",
quantity: "1"
}
];
class App extends React.Component {
constructor( props ) {
super( props );
this.state = {
products: this.props.products,
cart: this.props.products,
totalAmount: 0
};
this.handleRemoveProduct = this.handleRemoveProduct.bind( this );
this.handleChangeQuantity = this.handleChangeQuantity.bind( this );
this.sumTotalAmount = this.sumTotalAmount.bind( this );
}
handleRemoveProduct( id ) {
let cart = this.state.cart;
cart = cart.filter( ( product ) => {
return product.id != id;
} );
this.setState( {
cart
} );
this.sumTotalAmount();
}
handleChangeQuantity( e, id ) {
let cart = this.state.cart;
cart = cart.map( ( product ) => {
if (product.id == id ) {
product.quantity = e.target.value;
}
return product;
} );
this.setState( {
cart
} );
this.sumTotalAmount();
}
sumTotalAmount() {
this.setState( (prevState, props) => { return { totalAmount : prevState.cart.map(( product ) => {
return Number(product.quantity) * Number(product.price);
} ).reduce( ( total, current ) => total += current )}
})
}
render() {
return(
<div>
<div className="cart">
{
this.state.cart.map( ( item, index ) => {
return(
<Product key={index} item={item}
handleRemoveProduct={this.handleRemoveProduct}
handleChangeQuantity={this.handleChangeQuantity}
/>
)
})
}
</div>
<div className="cart__total">
Total amount - {this.state.totalAmount}
</div>
</div>
)
}
}
const Product = ( props ) => (
<div className="cart__product">
{props.item.title} <a href="#" onClick={() => props.handleRemoveProduct(props.item.id)}>Remove</a>
<input type="number" name="quantity" min="1" max={props.item.left} value={props.item.quantity} onChange={(e) => props.handleChangeQuantity(e, props.item.id)}/>
</div>
);
ReactDOM.render(<App products = {products} />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.development.js"></script>
<div id="root"></div>