如何避免';具有相同钥匙的儿童';在ReactJs组件中替换状态时
我已经创建了一个React组件,它在给定id数组的情况下呈现一组子元素。ID数组保持在父组件的状态,然后我基于ID运行一些ajax调用以获取要渲染的数据。获取的数据存储在状态为的单独数据数组中。渲染组件使用id作为键 ID可以根据组件外部的操作进行更改,因此我在组件上使用setState来替换数组。更新后的id状态可能包含一些与原始数组中相同的id。同时,我清空“数据数组”,以便再次呈现所有内容 当我这样做时,有时会收到关键警告: 警告:FlattChildren(…):遇到两个具有相同 钥匙子密钥必须是唯一的;当两个孩子共享一把钥匙时,只有 第一个孩子将被使用 新数组不包含任何重复项。那么为什么会发生这种情况,我能做些什么来避免这种情况呢 编辑:根据请求添加一些代码。注意:我正在使用。这可能是原因吗 初始状态: 渲染功能: 最后,在组件外部进行更新时:如何避免';具有相同钥匙的儿童';在ReactJs组件中替换状态时,reactjs,Reactjs,我已经创建了一个React组件,它在给定id数组的情况下呈现一组子元素。ID数组保持在父组件的状态,然后我基于ID运行一些ajax调用以获取要渲染的数据。获取的数据存储在状态为的单独数据数组中。渲染组件使用id作为键 ID可以根据组件外部的操作进行更改,因此我在组件上使用setState来替换数组。更新后的id状态可能包含一些与原始数组中相同的id。同时,我清空“数据数组”,以便再次呈现所有内容 当我这样做时,有时会收到关键警告: 警告:FlattChildren(…):遇到两个具有相同 钥匙子
movieBox.setState({
hasMore: true,
num: 0,
movieIds: filteredIds,
movies: []
});
我不会将来自后端的ID用作React中的键属性。如果您这样做了,那么您将依赖一些与组件有点远的逻辑来确保您的密钥是唯一的。如果它们的关键点不唯一,则可以中断react的渲染,因此这非常重要 在我看来,这就是为什么您应该坚持在for循环或类似的设置键属性中使用索引的原因。这样你就知道它们永远不会是非唯一的,而这正是最简单的方法 如果不知道您的ID是如何工作的,就不可能说出是什么导致了这里的非唯一冲突。然而,由于
键
只是允许React正确地识别元素,而不是其他任何东西,因此除了简单的计数或索引之外,它没有任何意义
var children = [];
for (var i=0; i<yourArray.length; i++) {
children.push(
<div key={i}>{yourArray[i].someProp}</div>
);
}
var children=[];
对于(var i=0;i我发现了我的错误,这与反应本身无关。这是一个典型的反应
由于可能存在重复,我将每个ajax响应存储在movieId上的window.localStorage中
在“有限滚动”中,列表中的每个项目都是通过调用loadMore函数按顺序绘制的。在此函数中,我进行了ajax调用,并将结果存储在浏览器缓存中。代码如下所示:
var cachedValue = window.localStorage.getItem(String(movieId));
var cachedData = cachedValue ? JSON.parse(cachedValue) : cachedValue;
if (cachedData != null) {
comp.drawNextMovie(cachedData);
} else {
$.ajax( {
type: "GET",
url: this.state.movieUrl + movieId,
contentType: "json",
success: function (movieData) {
window.localStorage.setItem(String(movieId), JSON.stringify(movieData));
comp.drawNextMovie(movieData);
}
});
}
你能发现错误吗?当ajax调用返回时,movieId不再是原来的样子。因此,我最终用错误的id存储数据,并得到一些奇怪的React警告。因为这是在InfiniteSroll模块调用的loadMore函数中完成的,所以我没有意识到该函数的范围没有正确确定
我通过添加一个来修复它。给出一个显示问题的代码的最小示例。这可能是一个简单的修复,但完全取决于您的代码。例外情况是项目可以重新排序,或插入/删除除结尾以外的任何位置。感谢您的输入。但它并没有解决我的问题。如果您使用React.Children.map
to遍历对象列表,您将如何获得要使用的索引号?您可以使用map
函数中的任何内容吗?还是您自己创建一个?@BenGrunfeld该索引将作为第二个参数传递给您提供给map
的函数。示例:@mheiber您在示例中甚至不使用key属性?这就是IIFE需要围绕您刚才描述的整个区块。
movieBox.setState({
hasMore: true,
num: 0,
movieIds: filteredIds,
movies: []
});
var children = [];
for (var i=0; i<yourArray.length; i++) {
children.push(
<div key={i}>{yourArray[i].someProp}</div>
);
}
var cachedValue = window.localStorage.getItem(String(movieId));
var cachedData = cachedValue ? JSON.parse(cachedValue) : cachedValue;
if (cachedData != null) {
comp.drawNextMovie(cachedData);
} else {
$.ajax( {
type: "GET",
url: this.state.movieUrl + movieId,
contentType: "json",
success: function (movieData) {
window.localStorage.setItem(String(movieId), JSON.stringify(movieData));
comp.drawNextMovie(movieData);
}
});
}