Waarschuwing: elk kind in een array of iterator moet een unieke ‘sleutel’-prop hebben. Controleer de rendermethode van `ListView`

Ik heb een app gebouwd met ReactNativezowel voor iOS als Android met een ListView. Wanneer de lijstweergave wordt gevuld met een geldige gegevensbron, wordt de volgende waarschuwing onderaan het scherm afgedrukt:

Waarschuwing: elk kind in een array of iterator moet een unieke “sleutel” hebben
steun. Controleer de rendermethode van ListView.

Wat is het doel van deze waarschuwing? Na het bericht linken ze naar deze pagina, waar hele andere dingen worden besproken die niets te maken hebben met native reageren, maar met webgebaseerde reactjs.

Mijn ListView is gebouwd met deze uitspraken:

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

Mijn gegevensbron bestaat uit zoiets als:

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

en de lijstview-rijen worden weergegeven met dingen zoals:

       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 werkt prima en zoals verwacht, behalve de waarschuwing die voor mij complete onzin lijkt te zijn.

Een sleutel-eigenschap toevoegen aan mijn “Detinessitem” -klasse loste het probleem niet op.

Dit is, wat echt wordt doorgegeven aan de lijstview als gevolg van “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: '' } ] },

Zoals één sleutel ziet, heeft elke record een sleuteleigenschap. De waarschuwing bestaat nog steeds.


Antwoord 1, autoriteit 100%

Ik heb al een tijdje precieshetzelfde probleem als jij, en na het bekijken van enkele van de bovenstaande suggesties, heb ik het probleem eindelijk opgelost.

Het blijkt (in ieder geval voor mij in ieder geval), dat ik een sleutel (een prop genaamd ‘sleutel’) nodig had voor het onderdeel dat ik terugstuur van mijn renderSeparator-methode. Het toevoegen van een sleutel aan mijn renderRow of renderSectionHeader deed niets, maar door het toe te voegen aan renderSeparator verdween de waarschuwing.

Hopelijk helpt dat.


Antwoord 2, autoriteit 86%

U moet een sleutelopgeven.

Probeer dit in uw ListView-rijen als u een sleuteleigenschap heeft:

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

Zo niet, probeer het item dan gewoon als sleutel toe te voegen:

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

Antwoord 3, autoriteit 38%

U kunt het aantal herhalingen (i) ook gebruiken als de key:

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

Antwoord 4, autoriteit 22%

Wijzig uw code van:

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

Aan:

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

Vervolgens opgelost.


Antwoord 5, autoriteit 13%

Voeg een prop-sleutel toe aan de render-rootcomponent van de lijst.

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

Antwoord 6, autoriteit 7%

Deze waarschuwing komt wanneer u geen sleutel aan uw lijstitems toevoegt. Volgens react js Docs –

Toetsen helpen React bepalen welke items zijn gewijzigd, toegevoegd of zijn
VERWIJDERD. Sleutels moeten worden gegeven aan de elementen in de array om te geven
de elementen een stabiele identiteit:

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

De beste manier om een sleutel te kiezen is door een tekenreeks te gebruiken die uniek identificeert
een lijstitem onder zijn broers en zussen. Meestal gebruikt u ID’s van uw
gegevens als sleutels:

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

Als je geen stabiele ID’s hebt voor weergegeven items, kun je de
itemindex als laatste redmiddel

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

Antwoord 7, autoriteit 6%

Controleer: key = undef !!!

Je hebt ook het waarschuwingsbericht ontvangen:

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

als uw code correct is, maar indien aan

<MyComponent key={someValue} />

someValue is niet gedefinieerd!!! Controleer dit eerst. U kunt uren besparen.


Antwoord 8, autoriteit 4%

Ik heb het opgelost door een eigenschap toe te voegen aan renderSeparator Component, de code is hier:

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

De sleutelwoorden van deze waarschuwing zijn “uniek”, sectionID + rowID retourneren een unieke waarde in ListView.


Antwoord 9, autoriteit 3%

Ervan uitgaande dat de methode renderDetailItem de volgende handtekeningheeft. ..

(rowData, sectionID, rowID, highlightRow) 

Probeer dit eens…

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

Antwoord 10, autoriteit 3%

De specifieke code die ik heb gebruikt om dit op te lossen was:

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

Ik voeg de specifieke code toe omdat de sleutels uniek moeten zijn, zelfs voor scheidingstekens. Als je iets soortgelijks doet, bijvoorbeeld als je dit op een constante zet, krijg je gewoon weer een vervelende fout over het hergebruik van sleutels. Als je JSX niet kent, kan het lastig zijn om de callback naar JS te maken om de verschillende onderdelen uit te voeren.

En op de ListView, uiteraard dit toevoegend:

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

Met dank aan coldbuffet en Nader Dabit die me op dit pad hebben gewezen.


Antwoord 11, autoriteit 2%

Dit is gebaseerd op mijn begrip. Hopelijk is het nuttig. Het zou een lijst met alle componenten moeten weergeven als het voorbeeld erachter. De root-tag van elk onderdeel moet een keyhebben. Het hoeft niet uniek te zijn. Het kan niet key=0, key='0', enz. zijn. Het lijkt erop dat de sleutel nutteloos is.

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

Antwoord 12

Je krijgt dezelfde foutmelding als je een lege tag <>hebt als het hoogste niveau van je structuur in een lus:

return <select>
    {Object.values(countries).map(c => {
        return (<>           // <== EMPTY TAG!
            <option value={c.id}>{c.name}</option>
            <States countryId={c.id} />
        </>)
    }
</select>

U kunt de volledige syntaxis van <React.Fragment>gebruiken in plaats van de korte <>en uw sleutel toevoegen aan de volledige tag:

import {Fragment} from 'react';
return <select>
    {Object.values(countries).map(c => {
        return (<Fragment key={c.id}> // You can also use <React.Fragment> without import
            <option value={c.id}>{c.name}</option>
            <States countryId={c.id} />
        </Fragment>)
    }
</select>

Antwoord 13

Het lijkt erop dat aan beide voorwaarden is voldaan, misschien is key(‘contact’) het probleem

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

Antwoord 14

Dit kan niet genoeg benadrukt worden:

Sleutels hebben alleen zin in de context van de omringende array.

“Als u bijvoorbeeld een ListItem-component extraheert, moet u de sleutel op de <ListItem />-elementen in de array houden in plaats van op het <li>-element in de ListItem zelf.” — https://reactjs.org/docs/ lists-and-keys.html#extracting-components-with-keys


Antwoord 15

Wat me over dit probleem struikelde, was dat ik dacht dat de behoefte aan een sleutel van toepassing was op wat lijkt op ‘echte’ of DOM HTML-elementen in tegenstelling tot JSX-elementen die ik heb gedefinieerd.

Natuurlijk met reageren we werken met een virtuele dom, zodat de reageer JSX-elementen we definiëren <MyElement>zijn net zo belangrijk als de elementen die eruit zien als echte DOM HTML-elementen zoals <div>.

is dat logisch?


16

In mijn geval gebruikte ik de Semantic UI React “Card” -weergave. Nadat ik een sleutel heb toegevoegd aan elke kaart die ik heb geconstrueerd, ging de waarschuwing weg, bijvoorbeeld:

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

17

Dit werkte voor mij.

<View>
    {
        array.map((element, index) => {
            return(
                <React.Fragment key= {`arrayElement${index}`}>
                    {element}
                </React.Fragment>
            );
        })
    }
</View>

18

Als u de <Fade in>–element voor een reageertoepassing gebruikt, voeg dan key={}kenmerk erin toe of u zult een fout in de console.

Other episodes