![](/img/trans.png)
[英]getDerivedStateFromProps, change of state under the influence of changing props
[英]Changing state is causing props to change
我正在制作一个网络应用程序,人们可以单击鸡尾酒并更改配方以使每种成分或多或少具有这种成分。 为此,我首先从API端点加载饮料数据库,然后为数据库中的每种饮料创建一个孩子,并将其“ drink”属性设置为定义饮料名称和配方的JSON对象。
每个孩子都有一个按钮弹出一个模态,该模态有一个按钮组来调整每种成分的量。 为此,我将饮料配方作为属性传递给模式,然后将其从道具复制到状态。
然后,当有人调整饮料配方时(他们可以为每种成分选择“低”,“常规”或“高”,我在模态上调用一个类函数,该函数将配方列表中成分的索引和一个常量传递给乘以原始配方。
在该函数中,我设置了一个与props.recipe相等的临时配方,然后将该因子乘以成分的原始量。 然后我通过调用this.State将已被该因素修改的临时配方复制到该状态。
但是正在发生的事情是,它似乎正在改变props.recipe以及state.recipe。
为什么会这样呢? 我不认为可以更改道具。
其次,还有更好的方法吗? 我是新来的响应者,这是我有史以来第一个Web应用程序。 以最简单的形式,我只是试图限制可以减少/增加的每种成分的数量,但仍然为最终用户提供更改它的选择。
这是打开控制台后的屏幕截图,因此您可以看到更改了“之前”和“之后”两者的方式,即使原始数量为3,也是如此。我按下了“高”按钮,使原始数量增加了一倍。配料,但是如果我再次打它,它将再次翻倍而不是保持在6(这是道具中存储的原始配料量的2倍)。
这是模态的代码:
import React from 'react';
import ReactDOM from 'react-dom';
import {Modal, ButtonGroup, Button, Table} from 'react-bootstrap';
export default class DrinkInfo extends React.Component {
constructor(props){
super(props);
this.state = {
recipe: props.drink.recipe,
};
console.log('Drink Info Initial Recipe is');
console.log(this.props);
}
adjustAmount(ingredient, level){
console.log('before change')
var tempRecipe = this.props.drink.recipe;
console.log(tempRecipe)
tempRecipe[ingredient].amount = level * tempRecipe[ingredient].amount;
//tempRecipe[ingredient].amount = level * this.props.drink.recipe[ingredient].amount;
console.log('after change')
console.log(tempRecipe)
this.setState({ recipe: tempRecipe});
}
render(){
const drinkName = this.props.drink.drink;
//console.log(this.state.recipe)
const recipeTableBody = this.state.recipe.map((di, value) => {
//console.log(di.ingredient);
return(
<tr key = {di.ingredient}>
<td>{value}</td>
<td>{di.ingredient}</td>
<td>{di.amount}</td>
<td>
<ButtonGroup>
<Button onClick={() => this.adjustAmount(value, 0.5)}> Low </Button>
<Button onClick={() => this.adjustAmount(value, 1)}> Regular </Button>
<Button onClick={() => this.adjustAmount(value, 2)}> High </Button>
</ButtonGroup>
</td>
</tr>
);
});
//{console.log('Creating Info Modal for: ' + this.props.drink.drink)}
const recipeTable = (
<Table striped bordered condensed hover>
<thead>
<tr>
<th>#</th>
<th>Ingredient</th>
<th>Amount</th>
<th>Adjust</th>
</tr>
</thead>
<tbody>
{recipeTableBody}
</tbody>
</Table>
)
return(
<div>
<Modal show={this.props.show} onHide={this.props.onHide} bsSize="large" aria-labelledby="contained-modal-title-sm">
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-sm"> {this.props.drink.drink} </Modal.Title>
</Modal.Header>
<Modal.Body>
<h4> {this.props.drink.drink} Recipe </h4>
{recipeTable}
</Modal.Body>
<Modal.Footer>
<Button onClick={this.props.onHide}>Close</Button>
</Modal.Footer>
</Modal>
</div>
);
}
}
正如有人提到的那样,请尝试使以后的问题更短,更简洁。 这样可以更轻松地伸出援助之手。
就是说,我想我在您的adjustAmount()
函数中发现了您的问题。
看一看:
adjustAmount(ingredient, level){
var tempRecipe = this.props.drink.recipe;
tempRecipe[ingredient].amount = level * tempRecipe[ingredient].amount;
this.setState({ recipe: tempRecipe});
}
您正在使用this.props.drink.recipe
并将其设置为tempRecipe
。 由于recipe
是一个对象,因此基本上可以在tempRecipe
创建对该对象的tempRecipe
。 换句话说, tempRecipe === recipe
。
这意味着,当您更改tempRecipe
,您也在更改recipe
。 从严格意义上讲,React不能让您更改道具,但它没有任何东西可以冻结它们。 JavaScript是JavaScript,因此它可以帮助您。
您应该做的是克隆this.props.drink.recipe
,然后使用克隆。
adjustAmount(ingredient, level){
var tempRecipe = Object.assign({}, this.props.drink.recipe);
tempRecipe[ingredient].amount = level * tempRecipe[ingredient].amount;
this.setState({ recipe: tempRecipe});
}
这将assign()
的所有特性,从recipe
,并将它们分配给新的对象,有效地克隆它。
重要说明 : Object.assign({}, someObj)
只会创建一个浅表副本。 如果您的对象看起来很深,而不是Object.assign()
,则应该获取或创建一个深层克隆对象。
只需获取其中之一,然后执行以下操作:
adjustAmount(ingredient, level){
var tempRecipe = deepClone(this.props.drink.recipe);
tempRecipe[ingredient].amount = level * tempRecipe[ingredient].amount;
this.setState({ recipe: tempRecipe});
}
其中有很多,所以我不会在这里重新实现它们。 包含它们的几个库是lodash,下划线或NPM中有一些独立库。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.