[英](React) How to update input field based on dynamically typed other fields’ calculation results
So I have this problem, banging my head to the wall for the last several days, where I have a simple form, there might be more than one divs with four inputs but they are all related to each other. 因此,我遇到了这个问题,在过去的几天里,我一直很努力地工作,这里有一个简单的表格,可能有多个输入多个div的div,但它们彼此相关。 What I'm trying to do is to calculate the last input's in a div value which is based on the rest of the inputs' value and are typed dynamically and then to
setState()
to return a new state. 我想做的是计算div值中的最后一个输入,该值基于其余输入的值并被动态键入,然后输入
setState()
以返回新状态。 I have handler functions (to add, remove or change value of input fields) which work when I don't need to handle this particular update. 我有处理程序功能(用于添加,删除或更改输入字段的值),该功能在我不需要处理此特定更新时可以工作。 Now here's the code:
现在这里是代码:
class App extends React.Component {
state = {
bank: 10,
totalPrice: 0,
hands: [
{
name: "hand1",
backPrice: 0,
bankPrice: 0,
commision: 0,
realPrice: 0
}
],
handCount: 1
};
componentDidUpdate(prevProps, prevState) {
const hands = this.state.hands;
// initialized variables needed to calculate a result
const totalPrice = hands.reduce((total, hand) => {
return (hand.backPrice || 1) * total;
}, 1);
// lastHandPrice is ALWAYS needed, it is the base of the rest of calculations
const lastHandPrice = (this.state.bank * totalPrice) /
(hands[hands.length - 1].bankPrice -
(hands[hands.length - 1].commision / 100));
const newHands = hands.reduceRight(
// calculation starts in reverse, with the first value being lastHandPrice
// it returns an array of number values reversed again to be in correct order
(newHands, hand, ind, array) => {
let prevHand = array[ind + 1];
let prevPrice = newHands[array.length - ind - 2];
if (hand == array[array.length - 1]) {
return newHands.concat(lastHandPrice)
} else {
return newHands.concat(
prevPrice * (1 - (prevHand.commision / 100)) /
(hand.bankPrice - (hand.commision / 100))
)
}
}, []
).reverse();
if (this.state.hands !== prevState.hands)
this.setState({
totalPrice: totalPrice,
hands: this.state.hands.map((hand, index) => {
return Object.assign(hand, {realPrice: newHands[index]})
})
})
}
There are four main input fields in a div, represented in state.hands
. div中有四个主要输入字段,以
state.hands
表示。 So this code works just perfect in my terminal but react throws me a Maximum update depth exceeded
error when I try the following: 因此,此代码在我的终端中工作得非常完美,但是当我尝试以下操作时,反应会引发我
Maximum update depth exceeded
错误:
Add a new hand to the array 向数组添加新手
Try to enter anything in the input 尝试在输入中输入任何内容
There's nothing more I can really do about it. 我真的无能为力了。 I tried a few other methods to achieve this, but I always get the same error.
我尝试了其他几种方法来实现此目的,但始终会遇到相同的错误。 It seems like some kind of loop starts to work but I just can't figure it out.
似乎某种循环开始起作用,但我无法弄清楚。 Why it won't let me to update
state.hands
? 为什么不让我更新
state.hands
?
Input change/add/or remove handlers are very predictable, just updating the needed value, adding a div of four input fields, and removing the selected div. 输入更改/添加/或删除处理程序非常可预测,只需更新所需的值,添加四个输入字段的div,然后删除所选的div。 To change the value I
map()
over the state.hands
and then Object.assign()
the property value I need to the object I need (hand1, hand2, etc). 要在
state.hands
更改map()
,然后在Object.assign()
更改所需的属性值,以更改所需的对象(hand1,hand2等)。
EDIT (the rest of the code): 编辑(其余代码):
handleInputChange = (event) => {
const handName = event.currentTarget.parentNode.getAttribute("name");
const handInput = event.currentTarget.getAttribute("name");
const value = event.currentTarget.value;
if (handInput === "bank" || handInput === "totalPrice") {
this.setState({
[handInput]: value
});
} else {
this.setState(prevState => ({
hands: prevState.hands.map(
hand => {
if (hand.name === handName) {
return Object.assign(hand, { [handInput]: value })
} else {
return hand
}
}),
}));
}
}
handleAddHand = () => {
const handCount = this.state.handCount;
const name = `hand${handCount + 1}`;
const hand = {
name,
backPrice: 0,
bankPrice: 0,
commision: 0,
realPrice: 0
};
this.setState(prevState => ({
hands: prevState.hands.concat({...hand}),
handCount: prevState.handCount + 1
})
);
}
handleRemoveHand = (event) => {
const handName = event.currentTarget.parentNode.getAttribute("name");
const handIndex = this.state.hands.findIndex(hand =>
hand.name === handName);
this.setState(prevState => ({
hands: [
...prevState.hands.slice(0, handIndex),
...prevState.hands.slice(handIndex + 1)
]
}));
}
render() {
const listHands = this.state.hands
.map(hand =>
<HandInputs
key={hand.name}
name={hand.name}
backPrice={hand.backPrice}
bankPrice={hand.bankPrice}
commision={hand.commision}
realPrice={hand.realPrice}
handleChange={this.handleInputChange}
removeHand={this.handleRemoveHand}
/>
);
return (
<div>
<input
name="bank"
value={this.state.bank}
onChange={this.handleInputChange}
/>
<input
name="totalPrice"
value={this.state.totalPrice}
onChange={this.handleInputChange}
/>
{listHands}
<button onClick={this.handleAddHand}>Add Hand</button>
</div>
);
}
function HandInputs(props) {
return (
<div name={props.name}>
<input type="text" value={props.backPrice}
name="backPrice" onChange={props.handleChange} />
<input type="text" value={props.bankPrice}
name="bankPrice" onChange={props.handleChange} />
<input type="text" value={props.commision}
name="commision" onChange={props.handleChange} />
<input type="text" value={props.realPrice}
name="realPrice" onChange={props.handleChange} />
{props.name !== "hand1" &&
<button onClick={props.removeLeg}>Remove leg</button>}
</div>
);
}
Because you call setState
in componentDidUpdate
it makes the component go over the update life cycle again and call componentDidUpdate
in a loop. 因为您在
componentDidUpdate
调用setState
,它使组件再次经过更新生命周期,并在循环中调用componentDidUpdate
。 Your check: if (this.state.hands !== prevState.hands)
will always be true
because you always create a new hands
array in state: 你的检查:
if (this.state.hands !== prevState.hands)
将永远是true
,因为你总是创建一个新的hands
在状态数组:
this.setState({
totalPrice: totalPrice,
hands: this.state.hands.map((hand, index) => { <-- always cause a new array
return Object.assign(hand, {realPrice: newHands[index]})
})
})
One solution for this is to use the callback
function as the second argument to setState
. 一种解决方案是将
callback
函数用作setState
的第二个参数。 This callback will be called after the change of the state and inside it you can use the state
as you used it in componentDidUpdate
. 状态更改后将调用此回调,并且可以在内部使用它,就像在
componentDidUpdate
使用state
一样。
// the same function as your componentDidUpdate
afterStateChange = () => {
const hands = this.state.hands;
// initialized variables needed to calculate a result
...
// you can call `setState` here (you don't need to check if the state is different from prevState
this.setState({
totalPrice: totalPrice,
hands: this.state.hands.map((hand, index) => {
return Object.assign(hand, { realPrice: newHands[index] });
})
});
And then for example you can use it here: 然后例如,您可以在这里使用它:
handleAddHand = () => {
const handCount = this.state.handCount;
const name = `hand${handCount + 1}`;
const hand = {
name,
backPrice: 0,
bankPrice: 0,
commision: 0,
realPrice: 0
};
this.setState(
prevState => ({
hands: prevState.hands.concat({ ...hand }),
handCount: prevState.handCount + 1
}),
this.afterStateChange <-- here
);
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.