Warnung: Jedes Kind in einem Array oder Iterator sollte eine eindeutige Schlüsselstütze haben. Überprüfen Sie die Rendermethode von "ListView"


97

Ich habe eine App mit ReactNative sowohl für iOS als auch für Android mit einem erstellt ListView. Wenn Sie die Listenansicht mit einer gültigen Datenquelle füllen, wird am unteren Bildschirmrand die folgende Warnung angezeigt:

Warnung: Jedes Kind in einem Array oder Iterator sollte eine eindeutige "Schlüssel" -Stütze haben. Überprüfen Sie die Rendermethode von ListView.

Was ist der Zweck dieser Warnung? Nach der Nachricht verlinken sie auf diese Seite , auf der verschiedene Dinge besprochen werden, die nichts mit der Reaktion auf native, sondern mit webbasierten Reaktionen zu tun haben.

Meine ListView basiert auf folgenden Anweisungen:

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

    );
}

Meine DataSource besteht aus:

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

Und die ListView-Zeilen werden mit folgenden Dingen gerendert:

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

Alles funktioniert gut und wie erwartet, bis auf die Warnung, die mir als völliger Unsinn erscheint.

Das Hinzufügen einer Schlüsseleigenschaft zu meiner "DetailItem" -Klasse hat das Problem nicht gelöst.

Dies ist, was als Ergebnis von "cloneWithRows" wirklich an die ListView übergeben wird:

_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: 'xxxxxxxxx@hotmail.com',
I/ReactNativeJS( 1293):           headline: 'Email',
I/ReactNativeJS( 1293):           icon: 'fontawesome|envelope' },
I/ReactNativeJS( 1293):         { key: 6, type: 'moreInfo', text: '', headline: '', icon: '' } ] },

Wie ein Schlüssel zeigt, hat jeder Datensatz eine Schlüsseleigenschaft. Die Warnung ist noch vorhanden.


1
Höchstwahrscheinlich DetailItembenötigen Sie Schlüssel. Wenn sie bereits eindeutige Schlüssel haben, müssen Sie die anderen Rendermethoden ( renderHeader, renderDetailItem, renderSeparator) anzeigen . Sie funktionieren einwandfrei und werden erwartet, bis die Datenquelle in irgendeiner Weise geändert wird (z. B. werden Zeilen entfernt). Zu diesem Zeitpunkt weiß React nicht, was mit ihnen zu tun ist, wenn sie keine eindeutige Kennung haben.
Pete TNT

Was meinst du mit "Schlüsseln"? Eine Eigenschaft namens "Schlüssel"?
Löschen Sie den


Es löst es nicht. Ich habe meiner Datenstruktur eine Schlüsseleigenschaft hinzugefügt und die ursprüngliche Frage mit detaillierteren Daten aktualisiert. Das Auflisten von einfachen Daten, die zur DataSource führen, hat einen Schlüssel für jeden Datensatz. Diese Warnung bleibt bestehen.
Löschen Sie den

Es könnte auch von den anderen Rendermethoden stammen (renderHeader, renderDetailItem, renderSeparator)
Pete TNT

Antworten:


87

Ich habe jetzt schon eine Weile genau das gleiche Problem wie Sie und nachdem ich mir einige der obigen Vorschläge angesehen habe, habe ich das Problem endlich gelöst.

Es stellte sich heraus (zumindest für mich), dass ich der Komponente, die ich von meiner renderSeparator-Methode zurückgebe, einen Schlüssel (eine Requisite namens 'key') geben musste. Das Hinzufügen eines Schlüssels zu meiner renderRow oder renderSectionHeader hat nichts bewirkt, aber das Hinzufügen zu renderSeparator hat die Warnung gelöscht.

Hoffentlich hilft das.


In meinem Fall habe ich gerade renderSeparator gelöscht und meinen <Separator> in den Hauptteil des renderRow-Rückgabewerts verschoben.
Bootscodierer

Das Gleiche gilt hier für die SectionList, müssen explizit eine Eigenschaft mit Namen Schlüsseln für jeden itemRN glücklich zu machen.
LeOn - Han Li

1
Bevor ich dies las, verschwendete ich ungefähr 8 Stunden damit, herauszufinden, was ich für ein Problem mit meinen JSON-Daten hielt. Wenn es einen Stapelüberlauf gäbe: Taco: Ich würde dir einen geben!
Hoekma

74

Sie müssen einen Schlüssel angeben .

Versuchen Sie dies in Ihren ListView-Zeilen, wenn Sie eine Schlüsseleigenschaft haben:

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

Wenn nicht, fügen Sie einfach das Element als Schlüssel hinzu:

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

33

Sie können auch die Iterationszahl (i) verwenden als key:

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

2
Dies funktioniert möglicherweise nicht, wenn sich das Array ändert. Diese Antwort erklärt es mit einem Beispiel: stackoverflow.com/a/43892905/960857
Chris

20

Ändern Sie Ihren Code von:

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

Zu:

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

Dann gelöst.


13

Fügen Sie der Rendering-Stammkomponente der Liste einen Requisitenschlüssel hinzu.

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

7

Diese Warnung wird angezeigt, wenn Sie Ihren Listenelementen keinen Schlüssel hinzufügen.

Mithilfe von Schlüsseln können Sie reagieren, um festzustellen, welche Elemente geändert, hinzugefügt oder entfernt wurden. Den Elementen innerhalb des Arrays sollten Schlüssel zugewiesen werden, um den Elementen eine stabile Identität zu verleihen:

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

Der beste Weg, einen Schlüssel auszuwählen, besteht darin, eine Zeichenfolge zu verwenden, die ein Listenelement unter seinen Geschwistern eindeutig identifiziert. Am häufigsten verwenden Sie IDs aus Ihren Daten als Schlüssel:

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

Wenn Sie keine stabilen IDs für gerenderte Elemente haben, können Sie den Elementindex als letzten Ausweg als Schlüssel verwenden

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

4

Ich habe es behoben, indem ich der renderSeparator-Komponente eine Eigenschaft hinzugefügt habe. Der Code ist hier:

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

Die Schlüsselwörter dieser Warnung sind "eindeutig". SectionID + rowID geben einen eindeutigen Wert in ListView zurück.


3

Angenommen, die renderDetailItem-Methode hat die folgende Signatur ...

(rowData, sectionID, rowID, highlightRow) 

Versuchen Sie das ...

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

3

Der spezifische Code, mit dem ich das behoben habe, war:

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

Ich füge den spezifischen Code hinzu, da die Schlüssel eindeutig sein müssen - auch für Trennzeichen. Wenn Sie etwas Ähnliches tun, z. B. wenn Sie dies auf eine Konstante setzen, wird nur ein weiterer ärgerlicher Fehler bezüglich der Wiederverwendung von Schlüsseln angezeigt. Wenn Sie JSX nicht kennen, kann das Erstellen des Rückrufs an JS zum Ausführen der verschiedenen Teile ziemlich schmerzhaft sein.

Und in der ListView wird dies offensichtlich angehängt:

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

Dank an Coldbuffet und Nader Dabit, die mich auf diesen Weg geführt haben.


3

Check: key = undef !!!

Sie haben auch die Warnmeldung erhalten:

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

Wenn Ihr Code vollständig ist, aber wenn aktiviert

<MyComponent key={someValue} />

someValue ist undefiniert !!! Bitte überprüfen Sie dies zuerst. Sie können Stunden sparen.


2

Hier basiert auf meinem Verständnis. Hoffentlich ist es hilfreich. Es soll eine Liste aller Komponenten als Beispiel dahinter rendern. Das Root-Tag jeder Komponente muss a haben key. Es muss nicht eindeutig sein. Es kann nicht sein key=0, key='0'usw. Es sieht der Schlüssel nutzlos ist.

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

Scheint, als ob beide Bedingungen erfüllt sind, vielleicht ist der Schlüssel ("Kontakt") das Problem

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

Nein, Kontakt ist kein Schlüssel. Dazwischen habe ich meiner Datenstruktur eine Immobilie namens "Schlüssel" hinzugefügt und meine Frage aktualisiert, wobei detailliertere Daten übergeben wurden. Nichts hilft. Die Warnung bleibt bestehen.
Löschen Sie den


0

Die Sache, die mich auf dieses Problem aufmerksam gemacht hat, war, dass ich dachte, dass die Notwendigkeit eines Schlüssels für "echte" oder DOM-HTML-Elemente im Gegensatz zu den von mir definierten JSX-Elementen gilt.

Natürlich arbeiten wir mit React mit einem virtuellen DOM, daher sind die von uns definierten React JSX-Elemente <MyElement>genauso wichtig wie die Elemente, die wie echte DOM-HTML-Elemente aussehen <div>.

Ist das sinnvoll?


0

In meinem Fall habe ich die Ansicht "Karte" von Semantic UI React verwendet. Nachdem ich jeder von mir erstellten Karte einen Schlüssel hinzugefügt hatte, verschwand die Warnung, zum Beispiel:

return (
        <Card fluid key={'message-results-card'}>
          ...
        </Card>
)

-1

Wenn Sie das <Fade in>Element für eine Reaktionsanwendung verwenden, fügen key={}Sie bitte auch ein Attribut hinzu, da sonst ein Fehler in der Konsole angezeigt wird.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.