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

Предупреждение: каждый дочерний элемент в массиве или итераторе должен иметь уникальную "ключевую" опору. Проверьте метод рендеринга `ListView`

Я создал приложение с ReactNative для iOS и Android с ListView. При заполнении представления списка действительным источником данных в нижней части экрана выводится следующее предупреждение:

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

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

Мой ListView построен с этими утверждениями:

render() {
    var store = this.props.store;

    return (

        <ListView
            dataSource={this.state.dataSource}
            renderHeader={this.renderHeader.bind(this)}
            renderRow={this.renderDetailItem.bind(this)}
            renderSeparator={this.renderSeparator.bind(this)}
            style={styles.listView}
            />

    );
}

Мой DataSource состоит из чего-то вроде:

    var detailItems = [];

    detailItems.push( new DetailItem('plain', store.address) );
    detailItems.push( new DetailItem('map', '') );

    if(store.telefon) {
        detailItems.push( new DetailItem('contact', store.telefon, 'Anrufen', 'fontawesome|phone') );
    }
    if(store.email) {
        detailItems.push( new DetailItem('contact', store.email, 'Email', 'fontawesome|envelope') );
    }
    detailItems.push( new DetailItem('moreInfo', '') );

    this.setState({
        dataSource: this.state.dataSource.cloneWithRows(detailItems)
    });

И ListView-Rows отображаются с такими вещами, как:

        return (
            <TouchableHighlight underlayColor='#dddddd'>
                <View style={styles.infoRow}>
                    <Icon
                                name={item.icon}
                                size={30}
                                color='gray'
                                style={styles.contactIcon}
                                />
                    <View style={{ flex: 1}}>
                        <Text style={styles.headline}>{item.headline}</Text>
                        <Text style={styles.details}>{item.text}</Text>
                    </View>
                    <View style={styles.separator}/>
                </View>
            </TouchableHighlight>
        );

Все работает нормально и, как и ожидалось, кроме предупреждения, которое кажется мне полной чепухой.

Добавление ключевого свойства в мой "DetailItem" -Class не решило проблему.

Вот что действительно будет передано ListView в результате "cloneWithRows":

_dataBlob: 
I/ReactNativeJS( 1293):    { s1: 
I/ReactNativeJS( 1293):       [ { key: 2,
I/ReactNativeJS( 1293):           type: 'plain',
I/ReactNativeJS( 1293):           text: 'xxxxxxxxxx',
I/ReactNativeJS( 1293):           headline: '',
I/ReactNativeJS( 1293):           icon: '' },
I/ReactNativeJS( 1293):         { key: 3, type: 'map', text: '', headline: '', icon: '' },
I/ReactNativeJS( 1293):         { key: 4,
I/ReactNativeJS( 1293):           type: 'contact',
I/ReactNativeJS( 1293):           text: '(xxxx) yyyyyy',
I/ReactNativeJS( 1293):           headline: 'Anrufen',
I/ReactNativeJS( 1293):           icon: 'fontawesome|phone' },
I/ReactNativeJS( 1293):         { key: 5,
I/ReactNativeJS( 1293):           type: 'contact',
I/ReactNativeJS( 1293):           text: '[email protected]',
I/ReactNativeJS( 1293):           headline: 'Email',
I/ReactNativeJS( 1293):           icon: 'fontawesome|envelope' },
I/ReactNativeJS( 1293):         { key: 6, type: 'moreInfo', text: '', headline: '', icon: '' } ] },

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

4b9b3361

Ответ 1

У меня уже была точно та же проблема, что и вы, и, рассмотрев некоторые из приведенных выше предложений, я, наконец, решил проблему.

Получается (по крайней мере, для меня в любом случае), мне нужно было предоставить ключ (prop под названием "ключ" ) к компоненту, который я возвращаю из метода renderSeparator. Добавление ключа к моему renderRow или renderSectionHeader ничего не делало, но добавив его в renderSeparator, предупреждение вышло.

Надеюсь, что это поможет.

Ответ 2

Вам нужно предоставить ключ.

Попробуйте сделать это в своих рядах ListView, если у вас есть свойство ключа:

<TouchableHighlight key={item.key} underlayColor='#dddddd'>

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

<TouchableHighlight key={item} underlayColor='#dddddd'>

Ответ 3

Вы также можете использовать счетчик итераций (i) как key:

render() {
    return (
      <ol>
        {this.props.results.map((result, i) => (
          <li key={i}>{result.text}</li>
        ))}
      </ol>
    );
}

Ответ 4

Измените свой код:

render() {
    return (
      <ol>
        {this.props.results.map((result) => (
          <li>{result.text}</li>
        ))}
      </ol>
    );
}

To:

render() {
    return (
      <ol>
        {this.props.results.map((result) => (
          <li key={result.id}>{result.text}</li>
        ))}
      </ol>
    );
}

Затем решается.

Ответ 5

Добавьте опору 'key' к корневому компоненту рендеринга списка.

<ScrollView>
      <List>
          {this.state.nationalities.map((prop, key) => {
             return (
               <ListItem key={key}>
                  <Text>{prop.name}</Text>
               </ListItem>
             );
          })}
      </List>
</ScrollView>

Ответ 6

Это предупреждение появляется, когда вы не добавляете ключ к своим элементам списка. Согласно реакции JS Docs -

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

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li key={number.toString()}>
    {number}
  </li>
);

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

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

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

const todoItems = todos.map((todo, index) =>
  // Only do this if items have no stable IDs
  <li key={index}>
    {todo.text}
  </li>
);

Ответ 7

Я исправил это, добавив свойство для компонента renderSeparator, код здесь:

_renderSeparator(sectionID,rowID){
    return (
        <View style={styles.separatorLine} key={"sectionID_"+sectionID+"_rowID_"+rowID}></View>
    );
}

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

Ответ 8

Предполагая, что метод renderDetailItem имеет следующую подпись...

(rowData, sectionID, rowID, highlightRow) 

Попробуйте сделать это...

<TouchableHighlight key={rowID} underlayColor='#dddddd'>

Ответ 9

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

  renderSeparator(sectionID, rowID, adjacentRowHighlighted) {
    return (
      <View style={styles.separator} key={'${sectionID}-${rowID}'}/>
    )
  }

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

И на ListView, очевидно, прикрепляя это:

<ListView
  style={styles.listview}
  dataSource={this.state.dataSource}
  renderRow={this.renderRow.bind(this)}
  renderSeparator={this.renderSeparator.bind(this)}
  renderSectionHeader={this.renderSectionHeader.bind(this)}/>

Благодарю Coldbuffet и Nader Dabit, которые указали мне этот путь.

Ответ 10

Проверьте: ключ = undef !!!

Вы также получили предупреждение:

Each child in a list should have a unique "key" prop.

если ваш код завершен правильно, но если на

<MyComponent key={someValue} />

someValue не определено !!! Пожалуйста, проверьте это сначала. Вы можете сэкономить часы.

Ответ 11

Похоже, что оба условия выполнены, возможно, ключ ("контакт") является проблемой

 if(store.telefon) {
    detailItems.push( new DetailItem('contact', store.telefon, 'Anrufen', 'fontawesome|phone') );
}
if(store.email) {
    detailItems.push( new DetailItem('contact', store.email, 'Email', 'fontawesome|envelope') );
}

Ответ 12

Это не может быть подчеркнуто достаточно:

Ключи имеют смысл только в контексте окружающего массива.

"Например, если вы извлекаете компонент ListItem, вы должны хранить ключ для элементов <ListItem/> в массиве, а не для элемента <li> в самом ListItem". - https://reactjs.org/docs/lists-and-keys.html#extracting-components-with-keys

Ответ 13

Здесь основано на моем понимании. Надеюсь, это полезно. Предполагается, что список всех компонентов должен отображаться как пример позади. Корневой тег каждого компонента должен иметь key. Это не должно быть уникальным. Это не может быть key=0, key='0' и т.д. Кажется, ключ бесполезен.

render() {
    return [
        (<div key={0}> div 0</div>),
        (<div key={1}> div 2</div>),
        (<table key={2}><tbody><tr><td> table </td></tr></tbody></table>),
        (<form key={3}> form </form>),
    ];
}

Ответ 14

Если вы используете элемент <Fade in> для реагирующего приложения, добавьте в него также атрибут key={} иначе вы увидите ошибку в консоли.