ReactJS:映射组件的构造函数调用了多少次?
我有一个React组件,它在另一个组件中使用Array.prototype.map多次渲染 第一个组件的构造函数应该被调用多少次?我期望的是映射数组的长度的倍,但似乎只调用了一次 在我的特定代码中,它是在最后一次渲染之前调用的 示例代码:ReactJS:映射组件的构造函数调用了多少次?,reactjs,constructor,components,render,array.prototype.map,Reactjs,Constructor,Components,Render,Array.prototype.map,我有一个React组件,它在另一个组件中使用Array.prototype.map多次渲染 第一个组件的构造函数应该被调用多少次?我期望的是映射数组的长度的倍,但似乎只调用了一次 在我的特定代码中,它是在最后一次渲染之前调用的 示例代码: class ComponentB extends Component { constructor(props) { super(props) // added upon first reply this.handleObjectAdd =
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');
}
render() {
console.log('ComponentA render() called');
return (
<input type="text" value={this.props.details.prop1}></input>
)
}
}
此外,无论数组元素的数量如何,构造函数的日志行始终显示在最后一个构造函数日志行之前
为什么日志输出如上所述?如果您有任何见解,我将不胜感激
这被标记为的副本,但它不是。我理解您的问题,即为什么当我将新元素放在数组的最开始处时,似乎为最后一个元素创建了新的React组件 原因是要使用索引的键 基于文档中的logiccheck部分,因为只有最后一个元素(新索引为oldLength+1)具有唯一的键,所以它将从头开始创建。而所有其他的都只是重新渲染和更新。换句话说,您的代码更新N-1个元素,而不是只创建1个新元素,而保留所有其他元素不变 要处理这个问题,您不应该依赖于键中的索引,而应该使用其他一些可预测的、稳定的和unqiue值。在你的情况下,这是prop1。然后将为第一个元素调用构造函数 这是最新版本
class ComponentB extends Component {
constructor(props) {
super(props) // added upon first reply
this.state = {
objects: []
};
}
handleObjectAdd = () => {
this.setState(oldState => ({
objects: [
{prop1: this.state.objects.length + 1},
...oldState.objects
]
}))
}
render() {
return (
<div>
<button onClick={this.handleObjectAdd}>ADD</button>
{this.state.objects.map(obj =>
<ComponentA key={obj.prop1} details={obj} />
)}
</div>
)
}
}
class ComponentA extends Component {
constructor(props) {
super(props) // added upon first reply
console.log('ComponentA constructor called');
}
render() {
console.log('ComponentA render() called');
return (
<input type="text" value={this.props.details.prop1}></input>
)
}
}
您的初始代码几乎没有语法错误,而变异状态directlyn从未这样做过,所以它在单击按钮后从未重新呈现。下次发帖时请检查代码,这样会使理解/回答更容易
[UPD]从下面的评论中提取了一些片段
而不是仅仅创建一个新的,并保持所有其他不变
React不尝试最小化操作计数。在比较[1,2,3]和[0,1,2,3]时,有两种可能的方法:要么“在开始时插入0,移动所有其他元素”,要么“将所有元素减量1,并在结束时额外插入3”。如果您提供良好的属性作为关键,React将选择第一个解决方案。但让key={index}表示“反应,使用第二种方法,我知道我在做什么”。React不会分析调用.setState之前运行的代码,它只依赖于键值。谢谢您的回答。我的错误是发布了一个较旧的代码,后来我修复了实际代码中的变异状态部分。我也很感谢您对这些键的解释,这加强了我对列表和键的理解。你回答了为什么只有一次调用构造函数,我很难理解为什么没有重复调用它。我的另一个问题是:当我将新元素添加到列表的开头时,为什么会在第二个元素到最后一个元素时调用它?我将在我的初始代码中保留错误。看,React不会尝试最小化操作计数。在比较[1,2,3]和[0,1,2,3]时,有两种可能的方法:要么“在开始时插入0,移动所有其他元素”,要么“将所有元素减量1,并在结束时额外插入3”。如果您提供良好的属性作为关键,React将选择第一个解决方案。但让key={index}表示“反应,使用第二种方法,我知道我在做什么”。React不会分析调用之前运行的代码。setState,它只依赖于键值。我想我现在理解了为什么在最后一次渲染之前调用它:最后一次渲染调用实际上是针对列表开头添加的最后一个元素,在本例中,不是针对列表中存在的最后一个元素。所以,我认为React调用现有元素的呈现,然后调用新元素的构造函数,然后调用新元素的呈现。没错。最后一个是创建的,下一个是呈现的。您对操作的最后评论对于理解有关键和索引的文档非常有帮助。谢谢
class ComponentB extends Component {
constructor(props) {
super(props) // added upon first reply
this.state = {
objects: []
};
}
handleObjectAdd = () => {
this.setState(oldState => ({
objects: [
{prop1: this.state.objects.length + 1},
...oldState.objects
]
}))
}
render() {
return (
<div>
<button onClick={this.handleObjectAdd}>ADD</button>
{this.state.objects.map(obj =>
<ComponentA key={obj.prop1} details={obj} />
)}
</div>
)
}
}
class ComponentA extends Component {
constructor(props) {
super(props) // added upon first reply
console.log('ComponentA constructor called');
}
render() {
console.log('ComponentA render() called');
return (
<input type="text" value={this.props.details.prop1}></input>
)
}
}