Hati-hati saat mengulangi array !!
Ini adalah kesalahpahaman umum bahwa menggunakan indeks elemen dalam array adalah cara yang dapat diterima untuk menekan kesalahan yang mungkin Anda kenal:
Each child in an array should have a unique "key" prop.
Namun, dalam banyak kasus tidak! Ini adalah anti-pola yang dalam beberapa situasi dapat menyebabkan perilaku yang tidak diinginkan .
Memahami key
prop
Bereaksi menggunakan key
prop untuk memahami hubungan Elemen-ke-DOM elemen, yang kemudian digunakan untuk proses rekonsiliasi . Oleh karena itu sangat penting bahwa kunci selalu tetap unik , jika tidak ada kesempatan bagus Bereaksi akan mencampur unsur-unsur dan bermutasi yang salah. Penting juga bahwa tombol-tombol ini tetap statis di seluruh rendering ulang untuk mempertahankan kinerja terbaik.
Yang sedang berkata, seseorang tidak selalu perlu menerapkan di atas, asalkan diketahui bahwa array benar-benar statis. Namun, menerapkan praktik terbaik dianjurkan sedapat mungkin.
Pengembang Bereaksi mengatakan dalam masalah GitHub ini :
- kuncinya sebenarnya bukan tentang kinerja, ini lebih tentang identitas (yang pada gilirannya mengarah pada kinerja yang lebih baik). nilai yang ditugaskan secara acak dan berubah bukan identitas
- Kami tidak dapat secara realistis memberikan kunci [otomatis] tanpa mengetahui bagaimana data Anda dimodelkan. Saya akan menyarankan mungkin menggunakan semacam fungsi hashing jika Anda tidak memiliki id
- Kami sudah memiliki kunci internal ketika kami menggunakan array, tetapi mereka adalah indeks dalam array. Saat Anda memasukkan elemen baru, kunci-kunci itu salah.
Singkatnya, a key
seharusnya:
Menggunakan key
prop
Sesuai dengan penjelasan di atas, pelajari sampel-sampel berikut dengan cermat dan cobalah untuk mengimplementasikan, bila mungkin, pendekatan yang direkomendasikan.
Buruk (Berpotensi)
<tbody>
{rows.map((row, i) => {
return <ObjectRow key={i} />;
})}
</tbody>
Ini bisa dibilang kesalahan paling umum yang terlihat ketika iterasi di atas array di Bereaksi. Pendekatan ini secara teknis tidak "salah" , itu hanya ... "berbahaya" jika Anda tidak tahu apa yang Anda lakukan. Jika Anda melakukan iterasi melalui array statis maka ini adalah pendekatan yang benar-benar valid (mis. Array tautan dalam menu navigasi Anda). Namun, jika Anda menambahkan, menghapus, memesan kembali, atau memfilter item, maka Anda harus berhati-hati. Lihatlah penjelasan terperinci ini dalam dokumentasi resmi.
class MyApp extends React.Component {
constructor() {
super();
this.state = {
arr: ["Item 1"]
}
}
click = () => {
this.setState({
arr: ['Item ' + (this.state.arr.length+1)].concat(this.state.arr),
});
}
render() {
return(
<div>
<button onClick={this.click}>Add</button>
<ul>
{this.state.arr.map(
(item, i) => <Item key={i} text={"Item " + i}>{item + " "}</Item>
)}
</ul>
</div>
);
}
}
const Item = (props) => {
return (
<li>
<label>{props.children}</label>
<input value={props.text} />
</li>
);
}
ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Dalam cuplikan ini kami menggunakan array non-statis dan kami tidak membatasi diri untuk menggunakannya sebagai tumpukan. Ini adalah pendekatan yang tidak aman (Anda akan melihat alasannya). Perhatikan bagaimana saat kita menambahkan item ke awal array (pada dasarnya unshift), nilai untuk masing-masing <input>
tetap di tempatnya. Mengapa? Karena key
tidak mengidentifikasi setiap item secara unik.
Dengan kata lain, pada awalnya Item 1
sudah key={0}
. Ketika kami menambahkan item kedua, item teratas menjadi Item 2
, diikuti oleh Item 1
sebagai item kedua. Namun, sekarang Item 1
sudah key={1}
dan tidak key={0}
lagi. Sebaliknya, Item 2
sekarang sudah key={0}
!!
Karena itu, React berpendapat bahwa <input>
unsur - unsurnya tidak berubah, karena Item
kunci dengan 0
selalu ada di atas!
Jadi mengapa pendekatan ini saja terkadang buruk?
Pendekatan ini hanya berisiko jika array entah bagaimana difilter, disusun ulang, atau item ditambahkan / dihapus. Jika selalu statis, maka sangat aman untuk digunakan. Misalnya, menu navigasi suka["Home", "Products", "Contact us"]
dapat dengan aman diulangi dengan metode ini karena Anda mungkin tidak akan pernah menambahkan tautan baru atau mengatur ulang.
Singkatnya, inilah saatnya Anda dapat menggunakan indeks dengan aman sebagai key
:
- Array bersifat statis dan tidak akan pernah berubah.
- Array tidak pernah difilter (menampilkan subset dari array).
- Array tidak pernah disusun ulang.
- Array digunakan sebagai tumpukan atau LIFO (last in, first out). Dengan kata lain, menambahkan hanya bisa dilakukan di akhir array (yaitu push), dan hanya item terakhir yang bisa dihapus (yaitu pop).
Seandainya kami, dalam cuplikan di atas, mendorong item yang ditambahkan ke akhir array, urutan untuk setiap item yang ada akan selalu benar.
Sangat buruk
<tbody>
{rows.map((row) => {
return <ObjectRow key={Math.random()} />;
})}
</tbody>
Meskipun pendekatan ini mungkin akan menjamin keunikan kunci, itu akan selalu memaksa bereaksi untuk membuat kembali setiap item dalam daftar, bahkan ketika ini tidak diperlukan. Ini solusi yang sangat buruk karena sangat memengaruhi kinerja. Belum lagi bahwa seseorang tidak dapat mengecualikan kemungkinan tabrakan kunci dalam acara yang Math.random()
menghasilkan angka yang sama dua kali.
Kunci yang tidak stabil (seperti yang diproduksi oleh Math.random()
) akan menyebabkan banyak instance komponen dan node DOM tidak perlu diciptakan kembali, yang dapat menyebabkan penurunan kinerja dan kehilangan status komponen anak.
Baik sekali
<tbody>
{rows.map((row) => {
return <ObjectRow key={row.uniqueId} />;
})}
</tbody>
Ini bisa dibilang pendekatan terbaik karena menggunakan properti yang unik untuk setiap item dalam dataset. Misalnya, jika rows
berisi data yang diambil dari basis data, seseorang dapat menggunakan Kunci Utama tabel ( yang biasanya merupakan nomor yang bertambah secara otomatis ).
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
Baik
componentWillMount() {
let rows = this.props.rows.map(item => {
return {uid: SomeLibrary.generateUniqueID(), value: item};
});
}
...
<tbody>
{rows.map((row) => {
return <ObjectRow key={row.uid} />;
})}
</tbody>
Ini juga merupakan pendekatan yang baik. Jika dataset Anda tidak berisi data apa pun yang menjamin keunikan ( misalnya, array nomor sewenang-wenang ), ada kemungkinan tabrakan kunci. Dalam kasus seperti itu, yang terbaik adalah secara manual menghasilkan pengidentifikasi unik untuk setiap item dalam dataset sebelum mengulanginya. Lebih disukai ketika memasang komponen atau ketika dataset diterima ( misalnya dari props
atau dari panggilan API async ), untuk melakukan ini hanya sekali , dan tidak setiap kali komponen dirender ulang. Sudah ada beberapa perpustakaan di luar sana yang dapat memberikan Anda kunci tersebut. Berikut ini salah satu contohnya: react-key-index .
key
properti unik . Ini akan membantu ReactJS untuk menemukan referensi ke simpul DOM yang sesuai dan memperbarui konten hanya di dalam mark-up tetapi tidak merender ulang seluruh tabel / baris.