小编典典

在ReactJs组件中替换状态时如何避免``具有相同键的孩子''

reactjs

我创建了一个React组件,该组件呈现给定ID数组的一组子元素。id的数组保持在父组件的状态,然后我根据id运行一些ajax调用以获取要渲染的数据。所获取的数据在该状态下存储在单独的数据数组中。呈现的组件
将id用作key

id可以根据组件外部的操作而更改,因此我在组件上使用setState替换数组。 更新后的id状态可能包含与原始数组中相同的id。
同时,我清空“数据数组”,以便再次呈现所有内容。

当我这样做时,有时会收到密钥警告:

警告:flattenChildren(…):遇到两个具有相同密钥的孩子。子键必须是唯一的;当两个孩子共享一个密钥时,将仅使用第一个孩子。

新数组不包含任何重复项。那么为什么会发生这种情况,我该怎么做才能避免这种情况?

编辑:根据要求添加了一些代码。注意:我正在使用Infinite
Scroll模块
。这可能是原因吗?

初始状态:

getInitialState: function() {
  return {
    hasMore: true,
    num: 0,
    movieIds: this.props.movieIds,
    movies: []
  };
},

渲染功能:

render: function() {
  var InfiniteScroll = React.addons.InfiniteScroll;

  return (
    <InfiniteScroll
        pageStart={0}
        loadMore={this.loadMore}
        threshold='20'
        hasMore={this.state.hasMore}>
        <ul className="movieList">
          {this.state.movies}
        </ul>
    </InfiniteScroll>       
);
}

简化加载更多:

comp = this;
$.ajax( {
  url: url,
  contentType: "json",
  success: function (data) {
    var m = createMovieLi(data);
    var updatedMovies = comp.state.movies;
    updatedMovies[num] = m;
    comp.setState({movies: updatedMovies});
  }
});

最后,在组件外进行更新时:

movieBox.setState({
  hasMore: true,
  num: 0,
  movieIds: filteredIds,
  movies: []
});

阅读 264

收藏
2020-07-22

共1个答案

小编典典

我发现了自己的错误,这与React本身无关。这是在循环中缺少javascript闭包的经典案例。

由于重复的可能性,我将每个ajax响应都存储在movieId上的window.localStorage中。还是我想。

在React Inifinite
Scroll中,通过调用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警告。因为这是在InfiniteScroll模块调用的loadMore函数内部完成的,所以我不知道此函数的作用域不正确。

我通过添加立即调用的函数expression来修复它。

2020-07-22