我正在编写没有redux的简单购物车系统。
预期行为:更改产品数量时更新总金额
问题:
0
我需要:优雅的解决方案。不是硬编码。
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() {
let cart = this.state.cart;
let totalAmount = cart.map( ( product ) => {
return Number(product.quantity) * Number(product.price);
} ).reduce( ( total, current ) => total += current );
this.setState( {
totalAmount
} );
}
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>
答案 0 :(得分:2)
实际上,问题是你在setState之后调用sum方法并且setState是异步的,所以当执行sum时,状态没有改变,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"));
&#13;
<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>
&#13;
答案 1 :(得分:2)
Bruno添加了一大块代码来帮助解决问题,来自:
Total amount - {this.state.totalAmount}
要:
Total amount - {this.state.cart.map( ( product ) => {
return Number(product.quantity) * Number(product.price)
}).reduce( ( total, current ) => total += current )}
问题是双重的:
1)totalAmount初始化为0,并且在您对购物车进行更改之前,不会调用sumTotalAmount来更新它。
2)totalAmount滞后,特别是在最后一次删除时,因为每次调用sumTotalAmount都依赖于状态,这可能不是最新的(Bruno提到的异步部分)。
我会将您的(更新的)购物车传递给sumTotalAmount,并在构造和更改时使用其输出来设置totalAmount:
constructor( props ) {
super( props );
this.handleRemoveProduct = this.handleRemoveProduct.bind( this );
this.handleChangeQuantity = this.handleChangeQuantity.bind( this );
this.sumTotalAmount = this.sumTotalAmount.bind( this );
this.state = {
products: this.props.products,
cart: this.props.products,
totalAmount: this.sumTotalAmount(this.props.products)
};
}
handleRemoveProduct( id ) {
let cart = this.state.cart;
cart = cart.filter( ( product ) => {
return product.id != id;
} );
this.setState( {
cart: cart,
totalAmount: this.sumTotalAmount(cart)
} );
//this.sumTotalAmount(cart);
}
// Make a similar change to handleChangeQuantity
sumTotalAmount(cart) {
//let cart = this.state.cart;
let totalAmount = cart.map( ( product ) => {
return Number(product.quantity) * Number(product.price);
} ).reduce( ( total, current ) => total += current );
//this.setState( {
// totalAmount
//} );
return totalAmount;
}
答案 2 :(得分:2)
setState
方法是异步的,因此this.sumTotalAmount()
几乎不会做任何事情。
您至少有三种方法来修复代码:
将sum函数作为回调参数传递给setState
(并在setState
中调用componentDidMount
)
this.setState({
cart: newCart
}, () => {
this.sumTotalAmount();
})
使sum函数变为纯函数并使用新的购物车状态和计算的总和调用setState
(您基本上缓存非透明处于状态)
this.setState({
cart: newCart,
sum: calculateSum(newCart),
})
将sum函数设为纯函数并仅在需要值时使用它(如果使用了memoization,在这种情况下,您将缓存透明地)
this.setState({
cart: newCart,
})
// in render...
<div className="cart__total">
Total amount - {calculateSum(this.state.cart)}
</div>
答案 3 :(得分:0)
1。this.setState
是异步的,所以当你调用函数sumTotalAmount时,状态不会得到更新,所以你会得到
即使您删除了一个项目,所有项目的总和。
2.最初你没有计算总和,所以显示总和为0。
因此,请尝试在sumTotalAmount
中调用该函数componentDidMount
。