web-dev-qa-db-fra.com

Avertissement: chaque enfant d'un tableau ou d'un itérateur doit avoir un accessoire "clé" unique. Vérifiez la méthode de rendu de `ListView`

J'ai construit une application avec ReactNative pour iOS et Android avec un ListView . Lorsque vous remplissez la liste avec une source de données valide, l'avertissement suivant est imprimé au bas de l'écran:

Avertissement: chaque enfant d'un tableau ou d'un itérateur doit avoir un accessoire "clé" unique. Vérifiez la méthode de rendu de ListView.

Quel est le but de cet avertissement? Après le message, ils renvoient à cette page , où sont abordées différentes choses qui n’ont rien à voir avec réactif, mais avec des réactions basées sur le Web.

Mon ListView est construit avec ces déclarations:

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}
            />

    );
}

Mon source de données consiste en quelque chose comme:

    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)
    });

Et les ListView-Rows sont rendus avec des choses comme:

        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>
        );

Tout fonctionne bien et comme prévu, à l'exception de l'avertissement qui semble être un non-sens total pour moi.

L'ajout d'une propriété-clé à mon "DetailItem" -Class n'a pas résolu le problème.

C'est ce qui sera réellement passé à ListView à la suite de "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: '' } ] },

Comme le montre une clé, chaque enregistrement a une propriété de clé. L'avertissement existe toujours.

68
delete

Cela fait un moment que j'ai exactement le même problème que vous et après avoir examiné certaines des suggestions ci-dessus, j'ai finalement résolu le problème.

En fin de compte (du moins pour moi), je devais fournir une clé (un accessoire appelé "clé") au composant que je reviens de ma méthode renderSeparator. L'ajout d'une clé à mon renderRow ou à renderSectionHeader n'a rien fait, mais l'ajouter à renderSeparator a fait disparaître l'avertissement.

J'espère que ça t'as aidé.

75
coldbuffet

Vous devez fournir un clé.

Essayez de faire ceci dans vos lignes ListView si vous avez une propriété de clé:

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

Sinon, essayez simplement d'ajouter l'élément en tant que clé:

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

Vous pouvez également utiliser le nombre d'itérations (i) en tant que key:

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

Changer votre code de:

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

À:

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

Alors résolu.

17
micsay

Ajoutez une prop 'clé' au composant racine de rendu de la liste.

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

Cet avertissement survient lorsque vous n’ajoutez pas de clé à vos éléments de la liste.

Les touches aide React identifient les éléments qui ont été modifiés, ajoutés ou supprimés. Des clés doivent être attribuées aux éléments à l'intérieur du tableau pour leur donner une identité stable:

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

La meilleure façon de choisir une clé consiste à utiliser une chaîne qui identifie de manière unique un élément de la liste parmi ses frères et sœurs. Le plus souvent, vous utiliseriez les identifiants de vos données comme clés:

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

Lorsque vous n'avez pas d'identifiant stable pour les éléments rendus, vous pouvez utiliser l'index des éléments comme clé en dernier recours.

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

Je l'ai corrigé en ajoutant une propriété à renderSeparator Component, le code est ici:

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

Les mots clés de cet avertissement sont "unique", sectionID + rowID renvoient une valeur unique dans ListView.

4
bocai

En supposant que la méthode renderDetailItem ait le signe signature suivante ...

(rowData, sectionID, rowID, highlightRow) 

Essayez de faire ça ...

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

Le code spécifique que j'ai utilisé pour résoudre ce problème était le suivant:

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

J'inclus le code spécifique car il faut que les clés soient uniques, même pour les séparateurs. Si vous faites quelque chose de similaire, par exemple, si vous définissez ceci sur une constante, vous obtiendrez juste une autre erreur ennuyeuse sur la réutilisation des clés. Si vous ne connaissez pas JSX, construire le rappel à JS pour exécuter les différentes parties peut s'avérer très pénible.

Et sur le ListView, attachant évidemment ceci:

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

Merci à coldbuffet et à Nader Dabit qui m’ont indiqué ce chemin.

3
Selly

Vérifier: clé = undef !!!

Vous avez aussi le message d'avertissement:

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

si votre code est complet à droite, mais si activé

<MyComponent key={someValue} />

une valeur n'est pas définie !!! Veuillez vérifier ceci en premier. Vous pouvez économiser des heures.

1
Gerd

Ici est basé sur ma compréhension. J'espère que c'est utile. Il est supposé rendre une liste de tous les composants comme exemple derrière. La balise racine de chaque composant doit avoir un key. Il n'est pas nécessaire que ce soit unique. Il ne peut s'agir de key=0, key='0', etc. Il semble que la clé soit inutile.

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>),
    ];
}
0
caot

On dirait que les deux conditions sont remplies, peut-être que la question clé ('contact')

 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') );
}
0
Shiva Acharjee

Cela ne peut pas être assez souligné:

Les clés n'ont de sens que dans le contexte du tableau environnant .

"Par exemple, si vous extrayez un composant ListItem, vous devez conserver la clé sur les éléments <ListItem /> du tableau plutôt que sur l'élément <li> du ListItem lui-même." - https://reactjs.org/docs/lists-and-keys.html#extracting-components-with-keys

0