我有一个React组件,可以在另一个组件内部使用Array.prototype.map()多次渲染。
第一个组件的构造函数应调用多少次?我期望的次数是映射数组的长度的多少倍,但似乎只调用了一次。
在我的特定代码中,它在最后一个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');
}
render() {
console.log('ComponentA render() called');
return (
<input type="text" value={this.props.details.prop1}></input>
)
}
}
对于包含5个元素的数组(所有ComponentA实例),我得到以下几行:
ComponentA render() called
ComponentA render() called
ComponentA render() called
ComponentA render() called
ComponentA constructor called
ComponentA render() called
此外,无论数组元素的数量如何,构造函数的日志行始终出现在最后一个构造函数日志行之前。
为什么这样的日志输出是?不胜感激。
它被标记为React Rerender dynamic Components (Solr)的副本,但不是。
答案 0 :(得分:0)
我理解您的问题是“为什么当我将新元素放入数组的开头时,似乎为最后一个元素创建了新的React组件?”
原因是您将key
与index
一起使用。
基于其逻辑(请在文档中检查Lists and Keys部分),因为只有最后一个元素(新索引为oldLength + 1
)具有唯一的key
,才可以从头开始创建。而其他所有都只是重新渲染和更新。换句话说,您的代码将更新N - 1
元素,而不仅仅是创建1个新元素,并保持所有其他元素不变。
要解决这个问题,您不应该依赖index
中的key
,而要使用其他一些可预测的,稳定的,毫无道理的值。您的情况是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>
)
}
}
您的初始代码几乎没有语法错误,并且直接具有突变状态(从不这样做),因此单击按钮后就不会重新呈现。下次发布问题时,请检查代码-这样可以使理解/回答更加容易。
[UPD]从下面的评论中提取了一些片段
而不是仅创建1个新的,并保持所有其他不变。
React不会尝试减少操作次数。比较[1,2,3]和[0,1,2,3]时,有2种可能的方法:“在开始时插入0,将其他所有内容移位”或“将所有元素减1,然后在3处插入3”结束'。如果您提供良好的属性作为关键,React会选择第一个解决方案。但是拥有key = {index}时,您的意思是说“反应,使用第二种方法,我知道我在做什么”。 React不会分析您在调用.setState之前运行的代码,它仅依赖于键值。