如何避免';具有相同钥匙的儿童';在ReactJs组件中替换状态时

如何避免';具有相同钥匙的儿童';在ReactJs组件中替换状态时,reactjs,Reactjs,我已经创建了一个React组件,它在给定id数组的情况下呈现一组子元素。ID数组保持在父组件的状态,然后我基于ID运行一些ajax调用以获取要渲染的数据。获取的数据存储在状态为的单独数据数组中。渲染组件使用id作为键 ID可以根据组件外部的操作进行更改,因此我在组件上使用setState来替换数组。更新后的id状态可能包含一些与原始数组中相同的id。同时,我清空“数据数组”,以便再次呈现所有内容 当我这样做时,有时会收到关键警告: 警告:FlattChildren(…):遇到两个具有相同 钥匙子

我已经创建了一个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);
      }
    });  
  }