Peringatan: Setiap anak dalam larik atau iterator harus memiliki properti "kunci" yang unik. Periksa metode render dari `ListView`


105

Saya membuat aplikasi dengan ReactNative baik untuk iOS dan android dengan file ListView. Saat mengisi listview dengan sumber data yang valid, peringatan berikut dicetak di bagian bawah layar:

Peringatan: Setiap anak dalam larik atau iterator harus memiliki properti "kunci" yang unik. Periksa metode render ListView.

Apa tujuan peringatan ini? Setelah pesan yang mereka tautkan halaman ini , di mana hal-hal yang berbeda dibahas yang tidak ada hubungannya dengan react native, tetapi dengan reactjs berbasis web.

ListView saya dibuat dengan pernyataan tersebut:

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

    );
}

Sumber Data saya terdiri dari sesuatu seperti:

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

Dan ListView-Rows dirender dengan hal-hal seperti:

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

Semuanya bekerja dengan baik dan seperti yang diharapkan, kecuali peringatan yang tampaknya sama sekali tidak masuk akal bagi saya.

Menambahkan properti kunci ke kelas "DetailItem" saya tidak menyelesaikan masalah.

Ini, apa yang sebenarnya akan diteruskan ke ListView sebagai hasil dari "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: 'xxxxxxxxx@hotmail.com',
I/ReactNativeJS( 1293):           headline: 'Email',
I/ReactNativeJS( 1293):           icon: 'fontawesome|envelope' },
I/ReactNativeJS( 1293):         { key: 6, type: 'moreInfo', text: '', headline: '', icon: '' } ] },

Seperti yang dilihat oleh salah satu kunci, setiap record memiliki properti kunci. Peringatan itu masih ada.


1
Kemungkinan besar Anda DetailItemperlu memiliki kunci. Jika mereka sudah memiliki kunci unik, Anda perlu menunjukkan metode render lainnya ( renderHeader, renderDetailItem, renderSeparator). Mereka berfungsi dengan baik dan diharapkan sampai sumber data diubah di suatu tempat (baris dihapus, misalnya) di mana React tidak akan tahu apa yang harus dilakukan dengan mereka ketika mereka tidak memiliki pengenal unik.
Pete TNT

Apa yang Anda maksud dengan "kunci"? Properti yang disebut "kunci"?
hapus


Itu tidak menyelesaikannya. Saya menambahkan properti kunci ke struktur data saya dan memperbarui pertanyaan asli dengan data yang lebih terperinci. Mencantumkan data biasa, yang menghasilkan DataSource, memiliki kunci per setiap record. Peringatan ini tetap ada.
hapus

Mungkin juga berasal dari metode render lain (renderHeader, renderDetailItem, renderSeparator)
Pete TNT

Jawaban:


95

Saya sudah punya persis masalah yang sama dengan Anda untuk sementara waktu sekarang, dan setelah melihat beberapa saran di atas, saya akhirnya menyelesaikan masalah tersebut.

Ternyata (setidaknya untuk saya), saya perlu memberikan kunci (prop yang disebut 'key') ke komponen yang saya kembalikan dari metode renderSeparator saya. Menambahkan kunci ke renderRow atau renderSectionHeader saya tidak melakukan apa-apa, tetapi menambahkannya ke renderSeparator membuat peringatan itu hilang.

Semoga membantu.


Dalam kasus saya, saya baru saja menghapus renderSeparator dan memindahkan <Separator> saya ke dalam tubuh nilai kembalian renderRow.
boatcoder

Hal yang sama di sini untuk SectionList, harus secara eksplisit menambahkan properti dengan kunci nama untuk masing-masing itemuntuk membuat RN senang.
LeOn - Han Li

1
Sebelum membaca ini, saya menyia-nyiakan waktu sekitar 8 jam untuk melacak apa yang saya pikir merupakan masalah dengan data JSON saya. Jika ada tumpukan melimpah: taco: Saya akan memberikan Anda satu!
hoekma

79

Anda perlu memberikan kunci .

Coba lakukan ini di Baris ListView Anda jika Anda memiliki properti utama:

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

Jika tidak, coba tambahkan item sebagai kunci:

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

1
saya lebih suka jawaban ini, karena memiliki kode sehingga saya dapat menyalin XD
Jovylle Bermudez

35

Anda juga dapat menggunakan hitungan iterasi (i) sebagai key:

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

2
Ini mungkin tidak berfungsi saat array berubah. Jawaban ini menjelaskannya dengan contoh: stackoverflow.com/a/43892905/960857
Chris

22

Ubah kode Anda dari:

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

Untuk:

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

Kemudian diselesaikan.


13

Tambahkan 'kunci' prop ke komponen akar rendering dari daftar.

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

6

Peringatan ini muncul ketika Anda tidak menambahkan kunci ke item daftar Anda. Sesuai react js Docs -

Tombol membantu React mengidentifikasi item mana yang berubah, ditambahkan, atau dihapus. Kunci harus diberikan ke elemen di dalam array untuk memberikan elemen identitas yang stabil:

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

Cara terbaik untuk memilih kunci adalah dengan menggunakan string yang secara unik mengidentifikasi item daftar di antara saudara kandungnya. Paling sering Anda akan menggunakan ID dari data Anda sebagai kunci:

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

Jika Anda tidak memiliki ID yang stabil untuk item yang dirender, Anda dapat menggunakan indeks item sebagai kunci sebagai upaya terakhir

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

4

Saya memperbaikinya dengan menambahkan properti ke renderSeparator Component, kodenya ada di sini:

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

Kata kunci peringatan ini adalah "unik", sectionID + rowID mengembalikan nilai unik di ListView.


4

Periksa: key = undef !!!

Anda juga mendapat pesan peringatan:

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

jika kode Anda lengkap benar, tetapi jika aktif

<MyComponent key={someValue} />

someValue tidak ditentukan !!! Silakan periksa ini dulu. Anda dapat menghemat waktu berjam-jam.


3

Dengan asumsi metode renderDetailItem memiliki tanda tangan berikut ...

(rowData, sectionID, rowID, highlightRow) 

Coba lakukan ini ...

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

3

Kode spesifik yang saya gunakan untuk memperbaiki ini adalah:

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

Saya menyertakan kode khusus karena Anda memerlukan kunci yang unik - bahkan untuk pemisah. Jika Anda melakukan sesuatu yang serupa misalnya, jika Anda menyetelnya ke sebuah konstanta, Anda hanya akan mendapatkan kesalahan yang mengganggu tentang penggunaan kembali kunci. Jika Anda tidak mengetahui JSX, membuat callback ke JS untuk mengeksekusi berbagai bagian bisa sangat merepotkan.

Dan di ListView, dengan jelas melampirkan ini:

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

Penghargaan untuk coldbuffet dan Nader Dabit yang mengarahkan saya ke jalan ini.


2

Ini berdasarkan pemahaman saya. Semoga bermanfaat. Ini seharusnya membuat daftar komponen apa pun sebagai contoh di belakang. Tag root dari setiap komponen harus memiliki file key. Tidak harus unik. Tidak mungkin key=0, key='0'dll. Sepertinya kuncinya tidak berguna.

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

Sepertinya kedua syarat tersebut terpenuhi, mungkin kuncinya ('kontak') adalah masalahnya

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

tidak, kontak bukanlah kunci. Di antara saya menambahkan properti nyata yang disebut "kunci" ke struktur data saya dan memperbarui pertanyaan saya melewati data yang lebih rinci. Tidak ada yang membantu. Peringatan itu tetap ada.
hapus


0

Hal yang membuat saya tersandung pada masalah ini adalah saya berpikir bahwa kebutuhan akan kunci diterapkan pada apa yang tampak seperti elemen 'asli' atau DOM HTML sebagai lawan dari elemen JSX yang telah saya tentukan.

Tentu saja dengan React kita bekerja dengan DOM virtual sehingga elemen React JSX yang kita definisikan <MyElement>sama pentingnya dengan elemen yang terlihat seperti elemen DOM HTML asli.<div> .

Apakah itu masuk akal?


0

Dalam kasus saya, saya menggunakan tampilan Semantic UI React "Card". Setelah saya menambahkan kunci ke setiap kartu yang saya buat, peringatan itu hilang, misalnya:

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

-1

Jika Anda menggunakan <Fade in>elemen untuk aplikasi react, tambahkan key={}atribut di dalamnya juga atau Anda akan melihat kesalahan di konsol.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.