this.setState() 被异步调用,因此您不能依赖 this.state 在调用 this.setState() 后立即引用更新的值。阅读FAQ on component state。
如果你想在状态更新后引用newPrice的更新值,你可以:
-
使用
componentDidUpdate() 生命周期方法。见https://reactjs.org/docs/react-component.html#componentdidupdate。
addIngredientHandler = (type) => {
let oldCount = this.state.ingredients[type];
let copyState = { ...this.state.ingredients };
let newPrice = 0;
copyState[type] = oldCount + 1;
this.setState((prevState) => {
newPrice = prevState.totalPrice + PRICES_OF_INGREDIENTS[type];
newPrice = Math.round(newPrice * 100) / 100;
return { ingredients: copyState, totalPrice: newPrice }
});
}
componentDidUpdate(prevProps, prevState) {
if (prevState.totalPrice !== this.state.totalPrice) {
this.updatePurchaseable(this.state.ingredients, this.state.totalPrice);
}
}
-
使用
this.setState() 的第二个参数。请参阅https://reactjs.org/docs/react-component.html#setstate 上的文档。
addIngredientHandler = (type) => {
let oldCount = this.state.ingredients[type];
let copyState = { ...this.state.ingredients };
let newPrice = 0;
copyState[type] = oldCount + 1;
this.setState((prevState) => {
newPrice = prevState.totalPrice + PRICES_OF_INGREDIENTS[type];
newPrice = Math.round(newPrice * 100) / 100;
return { ingredients: copyState, totalPrice: newPrice }
}, () => {
this.updatePurchaseable(this.state.ingredients, this.state.totalPrice);
});
}
-
使用
ReactDOM.flushSync()。见https://github.com/reactwg/react-18/discussions/21。
import { flushSync } from 'react-dom';
addIngredientHandler = (type) => {
let oldCount = this.state.ingredients[type];
let copyState = { ...this.state.ingredients };
let newPrice = 0;
copyState[type] = oldCount + 1;
flushSync(() => {
this.setState((prevState) => {
newPrice = prevState.totalPrice + PRICES_OF_INGREDIENTS[type];
newPrice = Math.round(newPrice * 100) / 100;
return { ingredients: copyState, totalPrice: newPrice }
});
});
this.updatePurchaseable(copyState, newPrice);
}
如果我要编写此方法,我建议使用componentDidUpdate 生命周期方法,因为这将确保总价格变化时始终调用updatePurchaseable。如果您只在事件处理程序内部调用updatePurchaseable,那么如果价格在该处理程序之外发生变化,您最终可能会遇到错误。
addIngredientHandler = (type) => {
this.setState(prevState => {
let totalPrice = prevState.totalPrice + PRICES_OF_INGREDIENTS[type];
totalPrice = Math.round(totalPrice * 100) / 100;
return {
ingredients: {
...prevState.ingredients,
[type]: prevState.ingredients[type] + 1,
},
totalPrice,
};
});
}
componentDidUpdate(prevProps, prevState) {
const { totalPrice, ingredients } = this.state;
if (prevState.totalPrice === totalPrice) {
/*
Bail early. This is a personal code style preference. It may
make things easier to read as it keeps the main logic on the
"main line" (un-nested / unindented)
*/
return;
}
/*
If `updatePurchaseable` is a class method then you don't need to
pass state to it as it will already have access to `this.state`.
If `updatePurchaseable` contains complicated business logic,
consider pulling it out into its own module to make it easier
to test.
*/
this.updatePurchaseable(ingredients, totalPrice);
}