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.
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é.
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'>
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>
);
}
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.
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>
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>
);
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.
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'>
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.
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.
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>),
];
}
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') );
}
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