React.js 与 'two children with the same key' 混淆
React.js confuse with 'two children with the same key'
我正在使用 React 在页面上安装两个相同的组件,
var SelectBox = React.createClass({
getDefaultProps: function() {
return {
value: []
};
},
getInitialState: function() {
return {checked: this.props.value,count: 1};
},
handleClick: function() {
var opt = this.state.checked;
opt.push({id: this.state.count, name: this.state.count});
this.setState({checked: opt, count: this.state.count + 1});
},
render: function() {
var that = this;
var options = this.state.checked.map(item => <option key={'checked-' + that.props.name + item.id} value={item.id}>{item.name}</option>);
return (
<div>
<select multiple={true}>
{options}
</select>
<button type="button" onClick={this.handleClick}>add</button>
</div>
);
}
});
React.render(
<SelectBox name='one'/>,
document.getElementById('one')
);
React.render(
<SelectBox name='two'/>,
document.getElementById('two')
);
然后点击'one'的按钮,没问题,但是当我点击'two'的按钮时,一些'one'出现在'two',为什么??这让我很困惑。控制台显示:
Warning: flattenChildren(...): Encountered two children with the same key, `.$checked-two1`. Child keys must be unique; when two children share a key, only the first child will be used.
但只是做一些改变
var a = [{id: 5, name: 5}];
React.render(
<SelectBox name='one' value={a}/>,
document.getElementById('one')
);
它工作正常。
发生什么事了?有什么问题还是bug?
不,这里没有错误,您渲染了组件的同一个实例两次,这意味着 'components' 共享相同的状态,但是当您传递不同的道具时,组件现在有两个状态跟踪。
哦,我找到了真正的原因,getDefaultProps
被调用一次并缓存,getDefaultProps()
返回的任何复杂对象将跨实例共享,而不是复制,所以所有SelectBox组件没有传递的显式值属性将在状态中共享相同的已检查数组引用。
在这种情况下,我应该写:
getInitialState: function() {
var tmp = this.props.value.concat();
return {checked: tmp, count: 1};
},
当我在列表样式的反应组件中设置键时,我似乎遇到了这个问题,并且传递给键的 ID 不是唯一的,正如错误描述所暗示的那样。
例如 2 个列表项的键为 1。
这通常是因为设置您的唯一 ID 的逻辑错误。
在我的示例中,我为应用程序状态使用了 redux 存储,并且我将项目的 ID 设置为 items.length + 1
,这是不正确的。
这导致了我上面的two children with the same key error
。为了修复它,我将每个新项目的 id 设置为 itemsAdded
随着时间推移到列表的数量。
它类似于数据库中的键,其中 id 不断递增,因此由于将它们全部删除,您可能在数据库中没有任何项目,但是下一个项目的 id 可能是 1000。
我正在使用 React 在页面上安装两个相同的组件,
var SelectBox = React.createClass({
getDefaultProps: function() {
return {
value: []
};
},
getInitialState: function() {
return {checked: this.props.value,count: 1};
},
handleClick: function() {
var opt = this.state.checked;
opt.push({id: this.state.count, name: this.state.count});
this.setState({checked: opt, count: this.state.count + 1});
},
render: function() {
var that = this;
var options = this.state.checked.map(item => <option key={'checked-' + that.props.name + item.id} value={item.id}>{item.name}</option>);
return (
<div>
<select multiple={true}>
{options}
</select>
<button type="button" onClick={this.handleClick}>add</button>
</div>
);
}
});
React.render(
<SelectBox name='one'/>,
document.getElementById('one')
);
React.render(
<SelectBox name='two'/>,
document.getElementById('two')
);
然后点击'one'的按钮,没问题,但是当我点击'two'的按钮时,一些'one'出现在'two',为什么??这让我很困惑。控制台显示:
Warning: flattenChildren(...): Encountered two children with the same key, `.$checked-two1`. Child keys must be unique; when two children share a key, only the first child will be used.
但只是做一些改变
var a = [{id: 5, name: 5}];
React.render(
<SelectBox name='one' value={a}/>,
document.getElementById('one')
);
它工作正常。 发生什么事了?有什么问题还是bug?
不,这里没有错误,您渲染了组件的同一个实例两次,这意味着 'components' 共享相同的状态,但是当您传递不同的道具时,组件现在有两个状态跟踪。
哦,我找到了真正的原因,getDefaultProps
被调用一次并缓存,getDefaultProps()
返回的任何复杂对象将跨实例共享,而不是复制,所以所有SelectBox组件没有传递的显式值属性将在状态中共享相同的已检查数组引用。
在这种情况下,我应该写:
getInitialState: function() {
var tmp = this.props.value.concat();
return {checked: tmp, count: 1};
},
当我在列表样式的反应组件中设置键时,我似乎遇到了这个问题,并且传递给键的 ID 不是唯一的,正如错误描述所暗示的那样。
例如 2 个列表项的键为 1。
这通常是因为设置您的唯一 ID 的逻辑错误。
在我的示例中,我为应用程序状态使用了 redux 存储,并且我将项目的 ID 设置为 items.length + 1
,这是不正确的。
这导致了我上面的two children with the same key error
。为了修复它,我将每个新项目的 id 设置为 itemsAdded
随着时间推移到列表的数量。
它类似于数据库中的键,其中 id 不断递增,因此由于将它们全部删除,您可能在数据库中没有任何项目,但是下一个项目的 id 可能是 1000。