Подтвердить что ты не робот

Как избежать "детей с одним ключом" при замене состояния в компоненте ReactJs

Я создал компонент React, который отображает набор подэлементов, заданных массивом идентификаторов. Массив идентификаторов хранится в состоянии родительского компонента, а затем я запускаю некоторые вызовы ajax на основе идентификаторов для извлечения данных для рендеринга. Полученные данные сохраняются в отдельном массиве данных в состоянии. Представленные компоненты используют ключ id.

Иды могут изменяться в зависимости от действий вне компонента, поэтому я использую setState для компонента для замены массива. Обновленное состояние id, вероятно, будет содержать некоторые из тех же идентификаторов, что и в исходном массиве. В то же время я опуская "массив данных", чтобы все снова отображалось.

Когда я это делаю, я иногда получаю предупреждение-ключ:

Предупреждение: flattenChildren (...): Встречались двое детей с одинаковыми ключ. Детские ключи должны быть уникальными; когда двое детей делят ключ, только будет использоваться первый ребенок.

Новый массив не содержит дубликатов. Так почему это происходит, и что я могу сделать, чтобы этого избежать?

Изменить: добавлен код по запросу. Примечание. Я использую модуль бесконечной прокрутки. Может ли это быть причиной этого?

Начальное состояние:

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

Ответ 1

Я понял свою ошибку, и это не имело никакого отношения к Реагу. Это был классический случай отсутствия закрытия javascript внутри цикла.

Из-за возможности дублирования я сохранил каждый ответ ajax в window.localStorage, на movieId. Или так я думал.

In React Inifinite Прокрутка каждого элемента в вашем списке выполняется последовательно с вызовом функции 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-call, movieId больше не является тем, что было. Поэтому я заканчиваю хранение данных неправильным идентификатором и получаю некоторые странные предупреждения React в ответ. Поскольку это было сделано внутри функции loadMore, вызванной модулем InfiniteScroll, я не знал, что эта функция не была должным образом охвачена.

Я исправил это, добавив Немедленно вызванное функциональное выражение.

Ответ 2

Я бы не использовал ID из back-end как ключевое свойство в React. Если вы это сделаете, вы полагаетесь на некоторую логику, которая немного удалена от вашего компонента, чтобы убедиться, что ваши ключи уникальны. Если они не уникальны, вы можете сломать реакцию, так что это очень важно.

Вот почему вы должны, по-моему, просто придерживаться использования индекса в цикле for или аналогично установленным свойствам ключа. Таким образом, вы знаете, что они никогда не могут быть неповторимыми, и это самый простой способ сделать именно это.

Не зная точно, как работают ваши идентификаторы, невозможно сказать, что вызывает здесь неединственное столкновение. Однако, поскольку key заключается в том, чтобы позволить React правильно идентифицировать элементы, и ничто другое, для него не имеет смысла быть чем-то другим, кроме простого подсчета или индекса.

var children = [];
for (var i=0; i<yourArray.length; i++) {
    children.push(
        <div key={i}>{yourArray[i].someProp}</div>
    );
}