我有一个组件(“ ComponentA”),该组件在另一个组件(“ ComponentB”)的render()内部的map()中多次渲染。
此外,我在ComponentB中有一个“ ADD”按钮,单击该按钮时(通过'unshift()方法)在其ComponentB的“ state.objects”数组(用于映射ComponentA实例)中预先放置一个对象。每个前置对象都有一个属性'prop1',我用它来设置ComponentA的输入文本值。
问题是我在ComponentA的每个实例的状态下都没有得到期望值:在所有情况下,该元素始终具有值“ 1”(我希望... 3、2、1)。
此外,我看到ComponentA的构造函数在每个映射循环中仅被调用一次,尤其是在最后一个实例的render()调用之前。
这是(简体)代码:
class ComponentB extends Component {
constructor(props) {
super(props) // added upon first reply
this.handleObjectAdd = this.handleObject.bind(this);
this.state.objects = [];
}
handleObjectAdd() {
this.state.objects.unshift({prop1: this.state.objects.length + 1});
}
render() {
return (
<div>
<button onClick={this.handleObjectAdd}>ADD</button>
{ this.state.objects.map((object, index) =>
<ComponentA key={index} details={object}/>
)
}
</div>
)
})
}
}
class ComponentA extends Component {
constructor(props) {
super(props) // added upon first reply
console.log('ComponentA constructor called');
this.state = { details: props.details };
}
render() {
console.log('ComponentA render() called, prop1 value is ' + this.state.details.prop1);
return (
<input type="text" value={this.state.details.prop1}></input>
)
}
}
因此,使用上面的代码,单击添加按钮一次,将记录以下内容:
ComponentA constructor called
ComponentA render() called, prop1 value is 1
第二次单击按钮将记录:
ComponentA render() called, prop1 value is 1
ComponentA constructor called'
ComponentA render() called, prop1 value is 1
第三次单击按钮将记录:
ComponentA render() called, prop1 value is 1
ComponentA render() called, prop1 value is 1
ComponentA constructor called'
ComponentA render() called, prop1 value is 1
...等等。
在ComponentA的所有实例中,输入文本值为“ 1”。
我的问题是:
1)我如何对其进行编码以获得所需的ComponentA递增值?
2)为什么在该特定位置(在最后一个渲染实例之前)仅一次调用了映射组件的构造函数?
注意: 上面的代码只是我实际代码的简化版本,仅显示了演示该问题的必要部分。
答案 0 :(得分:0)
您通过进行类似this.state.objects.unshift()
的操作来should never mutate the state directly-改用this.setState()
。当您直接在this.state
内修改数组或对象时,React不知道其中的某些值已更改。这回答了您的两个问题。因此,代替直接修改this.state.objects
:
this.state.objects.unshift({prop1: this.state.objects.length + 1});
您应该以不变的方式在数组前添加新项目:
const newItem = { prop1: this.state.objects.length + 1 };
this.setState({
objects: [newItem].concat(this.state.objects)
});
除此之外,您忘记在super(props)
和ComponentA
的构造函数中调用ComponentB
。另外,无需将传递的道具复制到ComponentA
内部的组件状态中-只需使用道具即可。您可以看到有效的代码和框here。
答案 1 :(得分:0)
此问题的修复来自使用以下代码:
<input value={this.props....} onChange={...} // first version
代替
<input value={this.state....} onChange={....} // second version
我以前认为第二个版本是正确的,并且第一个版本阻止了输入的可编辑性。但是似乎onChange上的存在使第一个版本正常工作(正确显示了初始值和编辑后的值,并允许进行编辑)