Zbudowałem aplikację z ReactNative zarówno na iOS, jak i Androida z rozszerzeniemListView
. Podczas wypełniania widoku listy prawidłowym źródłem danych na dole ekranu jest drukowane następujące ostrzeżenie:
Ostrzeżenie: każde dziecko w tablicy lub iteratorze powinno mieć unikalną właściwość „key”. Sprawdź metodę renderowania
ListView
.
Jaki jest cel tego ostrzeżenia? Po wiadomości odsyłają do tej strony , na której omawiane są różne rzeczy, które nie mają nic wspólnego z reagowaniem natywnym, ale z reakcjami internetowymi.
Mój ListView jest zbudowany z tych instrukcji:
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}
/>
);
}
Moje źródło danych składa się z czegoś takiego:
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)
});
A ListView-Rows są renderowane za pomocą rzeczy takich jak:
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>
);
Wszystko działa dobrze i zgodnie z oczekiwaniami, z wyjątkiem ostrzeżenia, które wydaje mi się kompletnym nonsensem.
Dodanie właściwości klucza do mojej klasy „DetailItem” nie rozwiązało problemu.
Oto co tak naprawdę zostanie przekazane do ListView w wyniku „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: '' } ] },
Jak widać z jednego klucza, każdy rekord ma właściwość klucza. Ostrzeżenie nadal istnieje.
źródło
DetailItem
potrzebujesz kluczy. Jeśli mają już unikalne klucze, musisz pokazać inne metody renderowania (renderHeader, renderDetailItem, renderSeparator
). Działają dobrze i są oczekiwane, dopóki źródło danych nie zostanie w jakiś sposób zmodyfikowane (na przykład wiersze zostaną usunięte), po czym React nie będzie wiedział, co z nimi zrobić, jeśli nie mają unikalnego identyfikatora.Odpowiedzi:
Od jakiegoś czasu mam dokładnie ten sam problem, co Ty i po przejrzeniu niektórych z powyższych sugestii w końcu go rozwiązałem.
Okazuje się (przynajmniej dla mnie), że potrzebowałem dostarczyć klucz (rekwizyt o nazwie „klucz”) do komponentu, który zwracam z mojej metody renderSeparator. Dodanie klucza do mojego renderRow lub renderSectionHeader nic nie dało, ale dodanie go do renderSeparator sprawiło, że ostrzeżenie zniknęło.
Mam nadzieję, że to pomoże.
źródło
SectionList
, trzeba jawnie dodać właściwość z kluczem nazwy dla każdego,item
aby uszczęśliwić RN.Musisz podać klucz .
Spróbuj zrobić to w swoich ListView Rows, jeśli masz właściwość klucza:
<TouchableHighlight key={item.key} underlayColor='#dddddd'>
Jeśli nie, spróbuj po prostu dodać element jako klucz:
<TouchableHighlight key={item} underlayColor='#dddddd'>
źródło
Możesz również użyć liczby iteracji (i) jako
key
:render() { return ( <ol> {this.props.results.map((result, i) => ( <li key={i}>{result.text}</li> ))} </ol> ); }
źródło
Zmień kod z:
render() { return ( <ol> {this.props.results.map((result) => ( <li>{result.text}</li> ))} </ol> ); }
Do:
render() { return ( <ol> {this.props.results.map((result) => ( <li key={result.id}>{result.text}</li> ))} </ol> ); }
Następnie rozwiązany.
źródło
Dodaj atrybut „klucz” do głównego składnika renderowania listy.
<ScrollView> <List> {this.state.nationalities.map((prop, key) => { return ( <ListItem key={key}> <Text>{prop.name}</Text> </ListItem> ); })} </List> </ScrollView>
źródło
To ostrzeżenie pojawia się, gdy nie dodajesz klucza do elementów listy. Zgodnie z odpowiedzią js Docs -
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> );
źródło
Naprawiłem to, dodając właściwość do renderSeparator Component, kod jest tutaj:
_renderSeparator(sectionID,rowID){ return ( <View style={styles.separatorLine} key={"sectionID_"+sectionID+"_rowID_"+rowID}></View> ); }
Słowa kluczowe tego ostrzeżenia to „unikalne”, identyfikator sekcji + identyfikator wiersza zwracają unikalną wartość w ListView.
źródło
Sprawdź: klucz = undef !!!
Otrzymałeś również ostrzeżenie:
Each child in a list should have a unique "key" prop.
jeśli twój kod jest kompletny poprawnie, ale jeśli jest włączony
someValue jest niezdefiniowana !!! Sprawdź to najpierw. Możesz zaoszczędzić godziny.
źródło
Zakładając, że metoda renderDetailItem ma następujący podpis ...
Spróbuj to zrobić ...
<TouchableHighlight key={rowID} underlayColor='#dddddd'>
źródło
Konkretny kod, którego użyłem, aby to naprawić, to:
renderSeparator(sectionID, rowID, adjacentRowHighlighted) { return ( <View style={styles.separator} key={`${sectionID}-${rowID}`}/> ) }
Dołączam konkretny kod, ponieważ potrzebujesz unikalnych kluczy - nawet w przypadku separatorów. Jeśli zrobisz coś podobnego, np. Jeśli ustawisz to na stałą, otrzymasz kolejny irytujący błąd dotyczący ponownego użycia kluczy. Jeśli nie znasz JSX, skonstruowanie wywołania zwrotnego do JS w celu wykonania różnych części może być dość uciążliwe.
I na ListView, oczywiście dołączając to:
<ListView style={styles.listview} dataSource={this.state.dataSource} renderRow={this.renderRow.bind(this)} renderSeparator={this.renderSeparator.bind(this)} renderSectionHeader={this.renderSectionHeader.bind(this)}/>
Podziękowania dla coldbuffeta i Nadera Dabita, którzy wskazali mi tę ścieżkę.
źródło
Tutaj jest oparte na moim zrozumieniu. Mam nadzieję, że to pomocne. Ma wyrenderować listę komponentów jako przykład. Znacznik główny każdego składnika musi mieć rozszerzenie
key
. Nie musi być wyjątkowy. Nie może byćkey=0
,key='0'
itd. Wygląda na to, że klucz jest bezużyteczny.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>), ]; }
źródło
Wydaje się, że oba warunki są spełnione, być może kluczowy („kontakt”) jest problemem
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') ); }
źródło
Nie można tego wystarczająco podkreślić:
Klucze mają sens tylko w kontekście otaczającej tablicy .
Na przykład, jeśli wyodrębniasz komponent ListItem, powinieneś zachować klucz w elementach <ListItem /> w tablicy, a nie w elemencie <li> w samym ListItem. " - https://reactjs.org/docs/lists-and-keys.html#extracting-components-with-keys
źródło
To, co mnie zaskoczyło, polegało na tym, że pomyślałem, że potrzeba klucza zastosowanego do czegoś, co wygląda jak „rzeczywiste” lub elementy HTML DOM, w przeciwieństwie do elementów JSX, które zdefiniowałem.
Oczywiście z Reactem pracujemy z wirtualnym DOM, więc zdefiniowane przez nas elementy React JSX
<MyElement>
są dla niego tak samo ważne, jak elementy, które wyglądają jak prawdziwe elementy HTML DOM<div>
.Czy to ma sens?
źródło
W moim przypadku korzystałem z widoku „Karta” reakcji semantycznej UI. Po dodaniu klucza do każdej skonstruowanej karty ostrzeżenie zniknęło, na przykład:
return ( <Card fluid key={'message-results-card'}> ... </Card> )
źródło
Jeśli używasz
<Fade in>
elementu dla aplikacji Reaguj, dodajkey={}
do niego również atrybut lub zobaczysz błąd w konsoli.źródło