在 ReactJs 组件中替换状态时如何避免“具有相同键的子项" [英] How to avoid 'children with same key' when replacing state in ReactJs component

查看:47
本文介绍了在 ReactJs 组件中替换状态时如何避免“具有相同键的子项"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个 React 组件,它根据给定的 id 数组呈现一组子元素.id 数组保持在父组件的状态,然后我根据 id 运行一些 ajax 调用来获取数据以进行渲染.获取的数据存储在状态中的单独数据数组中.呈现的组件使用 id 作为键.

I have created a React Component that renders a set of sub-elements given an array of ids. The array of ids is kept in the state of the parent component, and then I run some ajax calls based on the ids to fetch data to render. The fetched data is stored in a separate data array in the state. The rendered components use the id as key.

ids 可以根据组件外部的动作而改变,所以我在组件上使用 setState 来替换数组.更新后的 id-state 可能包含一些与原始数组中相同的 id. 同时我清空数据数组",以便再次呈现所有内容.

The ids can change based on actions outside of the component, so I use setState on the component to replace the array. The updated id-state will probably contain some of the same ids as the in the original array. At the same time I empty the 'data array' so that everything will be rendered again.

当我这样做时,我有时会收到关键警告:

When I do this I sometimes get the key-warning:

警告:flattenChildren(...):遇到两个孩子钥匙.子键必须是唯一的;当两个孩子共用一把钥匙时,只有将使用第一个孩子.

Warning: flattenChildren(...): Encountered two children with the same key. Child keys must be unique; when two children share a key, only the first child will be used.

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

The new array does not contain any duplicates. So why does it happen, and what can I do to avoid this?

根据要求添加了一些代码.注意:我正在使用 无限滚动模块.这可能是导致它的原因吗?

Added some code by request. Note: I am using the Infinite Scroll module. Could this be causing it?

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: []
});

推荐答案

我发现了我的错误,它与 React 本身无关.这是循环内缺少javascript闭包的经典案例.

I figured out my mistake, and it had nothing to do with React per se. It was a classic case of missing javascript closure inside a loop.

由于存在重复的可能性,我将每个 ajax 响应存储在 window.localStorage 中的 movieId 上.或者我是这么想的.

Because of the possibility of duplicates I stored each ajax response in window.localStorage, on the movieId. Or so I thought.

在 React Infinite Scroll 中,列表中的每个项目都是通过调用 loadMore 函数按顺序绘制的.在这个函数中,我执行了 ajax 调用,并将结果存储在浏览器缓存中.代码如下所示:

In React Inifinite Scroll each item in your list is drawn sequentially with a call to the loadMore-function. Inside this function I did my ajax call, and stored the result in the browser cache. The code looked something like this:

  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 函数中完成的,所以我不知道这个函数的作用域不正确.

Can you spot the mistake? When the ajax-call returns, movieId is no longer what is was. So I end up storing the data by the wrong id, and get some strange React warnings in return. Because this was done inside the loadMore function called by the InfiniteScroll-module, I was not aware that this function was not properly scoped.

我通过添加一个立即调用的函数表达式来修复它.

I fixed it by adding a Immediately-invoked function expression.

这篇关于在 ReactJs 组件中替换状态时如何避免“具有相同键的子项"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆