Понимание уникальных ключей для детей массива в React.Яш

Я создаю компонент React, который принимает источник данных JSON и создает сортируемую таблицу.
Каждая из динамических строк данных имеет уникальный ключ, назначенный ему, но я все еще получаю ошибку:

каждый ребенок в массиве должен иметь уникальный" ключ " prop.
Проверьте метод рендеринга TableComponent.

мой TableComponent рендер метод возвращает:

<table>
  <thead key="thead">
    <TableHeader columns={columnNames}/>
  </thead>
  <tbody key="tbody">
    { rows }
  </tbody>
</table>

на TableHeader компонент представляет собой одну строку, а также имеет ему присвоен уникальный ключ.

каждого row на rows построен из компонента с уникальным ключом:

<TableRowItem key={item.id} data={item} columns={columnNames}/>

и TableRowItem выглядит так:

var TableRowItem = React.createClass({
  render: function() {

    var td = function() {
        return this.props.columns.map(function(c) {
          return <td key={this.props.data[c]}>{this.props.data[c]}</td>;
        }, this);
      }.bind(this);

    return (
      <tr>{ td(this.props.item) }</tr>
    )
  }
});

что вызывает ошибку уникального ключа prop?

7 ответов


вы должны добавить ключ к каждому ребенку а также каждый элемент внутри детей.

этот способ React может обрабатывать Минимальное изменение DOM.

в вашем коде, каждый <TableRowItem key={item.id} data={item} columns={columnNames}/> пытается отобразить некоторых детей внутри них без ключа.

Регистрация .

Попробуйте удалить key={i} С <b></b> элемент внутри div (и проверьте консоль).

в образце, если мы не даем ключ к <b> элемент и мы хотим обновить только на object.city, React должен повторно отобразить всю строку против только элемента.

вот код:

var data = [{name:'Jhon', age:28, city:'HO'},
            {name:'Onhj', age:82, city:'HN'},
            {name:'Nohj', age:41, city:'IT'}
           ];

var Hello = React.createClass({

    render: function() {

      var _data = this.props.info;
      console.log(_data);
      return(
        <div>
            {_data.map(function(object, i){
               return <div className={"row"} key={i}> 
                          {[ object.name ,
                             // remove the key
                             <b className="fosfo" key={i}> {object.city} </b> , 
                             object.age
                          ]}
                      </div>; 
             })}
        </div>
       );
    }
});

React.render(<Hello info={data} />, document.body);

реагировать документация о важности ключей в выверке:ключи


будьте осторожны при итерации по массивам!!

это распространенное заблуждение, что использование индекса элемента в массиве является приемлемым способом подавления ошибки, с которой вы, вероятно, знакомы:

Each child in an array should have a unique "key" prop.

однако, во многих случаях это не так! Это анти-шаблон, что в некоторые ситуации приводят к нежелательное поведение.


понимание the key prop

React использует key prop для понимания отношения компонента к элементу DOM, которое затем используется для процесс примирения. Поэтому очень важно, чтобы ключ всегда остается уникальный, в противном случае есть хороший шанс, что React смешает элементы и мутирует неправильный. Также важно, чтобы эти ключи остаются статичными на протяжении всех рендеров для того, чтобы поддерживайте лучшую производительность.

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

разработчик React сказал в этот вопрос GitHub:

  • ключ на самом деле не о производительности, это больше о идентичности (что, в свою очередь, приводит к лучшей производительности). случайно назначенные и изменяющиеся значения не являются identity
  • мы не можем реально предоставить ключи [автоматически], не зная, как моделируются ваши данные. Я бы предложил использовать какую-то функцию хэширования, если у вас нет ids
  • у нас уже есть внутренние ключи, когда мы используем массивы, но их индекс в массиве. Когда вы вставляете новый элемент, эти ключи неверны.

короче говоря, a key должны быть:

  • уникальный - ключ не может быть идентична компонент sibling.
  • Static - ключ никогда не должен меняться между отрисовками.


С помощью key prop

в соответствии с приведенным выше объяснением внимательно изучите следующие образцы и попробуйте реализовать, когда это возможно, рекомендуемый подход.


плохо (Потенциально)

<tbody>
    {rows.map((row, i) => {
        return <ObjectRow key={i} />;
    })}
</tbody>

это, возможно, самая распространенная ошибка, наблюдаемая при итерации по массиву в React. Этот подход технически не "неправильные", это просто... "опасные" если вы не знаете, что вы делаете. Если вы выполняете итерацию через статический массив, то это совершенно правильный подход (например, массив ссылок в меню навигации). Однако, если вы добавляете, удаляете, переупорядочиваете или фильтруете элементы, вам нужно быть осторожный. Взгляните на это подробное объяснение в официальной документации.

class MyApp extends React.Component {
  constructor() {
    super();
    this.state = {
      arr: ["Item 1"]
    }
  }
  
  click = () => {
    this.setState({
      arr: ['Item ' + (this.state.arr.length+1)].concat(this.state.arr),
    });
  }
  
  render() {
    return(
      <div>
        <button onClick={this.click}>Add</button>
        <ul>
          {this.state.arr.map(
            (item, i) => <Item key={i} text={"Item " + i}>{item + " "}</Item>
          )}
        </ul>
      </div>
    );
  }
}

const Item = (props) => {
  return (
    <li>
      <label>{props.children}</label>
      <input value={props.text} />
    </li>
  );
}

ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

в этом фрагменте мы используем нестатический массив, и мы не ограничиваемся его использованием в качестве стека. Это небезопасный подход (вы увидите, почему). Обратите внимание, как мы добавляем элементы в начало массива (в основном unshift), значение для каждого <input> остается на месте. Почему? Потому что key не однозначно идентифицирует каждый элемент.

другими словами, сначала Item 1 и key={0}. Когда мы добавляем второй элемент, верхний элемент становится Item 2, следовал по Item 1 как второй пункт. Однако теперь Item 1 и key={1}, а не


предупреждение: каждый ребенок в массиве или итераторе должен иметь уникальный" ключевой " prop.

это предупреждение, поскольку для элементов массива, которые мы собираемся перебирать, потребуется уникальное сходство.

React обрабатывает итерацию отрисовки компонентов в виде массивов.

лучший способ решить эту проблему-предоставить индекс для элементов массива, которые вы собираетесь перебирать.например:

class UsersState extends Component
    {
        state = {
            users: [
                {name:"shashank", age:20},
                {name:"vardan", age:30},
                {name:"somya", age:40}
            ]
        }
    render()
        {
            return(
                    <div>
                        {
                            this.state.users.map((user, index)=>{
                                return <UserState key={index} age={user.age}>{user.name}</UserState>
                            })
                        }
                    </div>
                )
        }

index-это встроенный реквизит React.


просто добавить уникальный ключ на компоненты

data.map((marker)=>{
    return(
        <YourComponents 
            key={data.id}     // <----- unique key
        />
    );
})

я исправил это, используя Guid для каждого ключа, как это: Создание Guid:

guid() {
    return this.s4() + this.s4() + '-' + this.s4() + '-' + this.s4() + '-' +
        this.s4() + '-' + this.s4() + this.s4() + this.s4();
}

s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
        .toString(16)
        .substring(1);
}

и затем присвоение этого значения маркерам:

{this.state.markers.map(marker => (
              <MapView.Marker
                  key={this.guid()}
                  coordinate={marker.coordinates}
                  title={marker.title}
              />
          ))}

Пример: Правильное Использование Ключа

function ListItem(props) {
  // Correct! There is no need to specify the key here:
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Correct! Key should be specified inside the array.
    <ListItem key={number.toString()}
              value={number} />

  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

это предупреждение, но адресация это сделает реагирует рендеринга гораздо быстрее,

это так React необходимо однозначно идентифицировать каждый элемент в списке. Скажем, если состояние элемента этого списка изменяется в Reacts Virtual DOM затем React должен выяснить, какой элемент был изменен и где в DOM он должен измениться, чтобы браузер DOM был синхронизирован с виртуальным DOM Reacts.

как решение просто вводим key атрибут для каждого li - тег. Это key должно быть уникальным значением для каждого элемента.