Halo semuanya. Artikel ini adalah tentang pendelegasian acara dalam JavaScript dan implementasinya di react.js.

Tentang apa itu sebenarnya? Kenapa dan mengapa?
Untuk memulai, mari kita bahas secara singkat:
- apa itu acara;
- bagaimana distribusi terjadi;
- Memproses DOM Level 2 dengan contoh dalam JavaScript;
Dan akhirnya: mengapa tidak melupakan delegasi dalam Bereaksi.
Acara
JavaScript dan HTML saling berinteraksi melalui acara. Setiap acara berfungsi untuk memberi tahu JavaScript bahwa ada sesuatu yang terjadi di jendela dokumen atau browser. Untuk menangkap peristiwa ini, kita membutuhkan pendengar (pendengar), penangan seperti itu yang dipicu dalam acara suatu peristiwa.
Propagasi Acara
Memesan Memecahkan masalah: bagaimana cara memahami bagian halaman yang dimiliki acara tersebut? Dua metode diimplementasikan: di Internet Explorer, "event bubbling," dan di Netscape Communicator, "event hooking."
Gelembung acara
Dalam kasus ini, acara dipicu pada simpul terdalam di pohon dokumen, setelah itu naik melalui hierarki ke jendela itu sendiri.
<!DOCTYPE html> <html> <head> <title>Some title</title> </head> <body> <div id="myDiv">Click Me</div> </body> </html>
Dalam hal ini akan ada urutan sebagai berikut:
- elemen div
- elemen tubuh
- elemen html
- dokumen
- jendela
Sekarang berselancar didukung oleh semua browser modern, meskipun dengan implementasi yang berbeda.
Dalam hal intersepsi peristiwa, yang terjadi adalah yang sebaliknya:
- jendela
- dokumen
- elemen html
- elemen tubuh
- elemen div
Diperkirakan acara tersebut dapat diproses sebelum mencapai elemen target (seperti yang diputuskan dalam Netscape kemudian mengambil semua browser modern).
Sebagai hasilnya, kami memiliki struktur berikut untuk mendistribusikan acara DOM:
- jendela
- dokumen
- elemen html
- elemen tubuh // fase intersepsi berakhir
- elemen div // fase target
- elemen tubuh // fase pendakian dimulai
- elemen html
- dokumen
- jendela
Skema ini dibagi menjadi tiga fase: fase intersepsi - peristiwa dapat dicegat sebelum mengenai elemen, fase target - pemrosesan oleh elemen target dan fase naik - untuk melakukan tindakan final apa pun sebagai respons terhadap peristiwa tersebut.
Jadi, kita beralih ke pemrosesan acara
Mari kita lihat contoh khas penanganan acara di JavaScript.
const btn = document.getElementById('myDiv') btn.addEventListener("click", handler)
Semua tidak akan berarti apa-apa, tetapi di sini kita mengingat IE tercinta yang berlangganan acara menggunakan attachEvent, dan menghapus detachEvent. Dan Anda dapat berlangganan ke acara tersebut beberapa kali. Dan jangan lupa bahwa dengan menandatangani fungsi anonim, kami tidak memiliki kesempatan untuk berhenti berlangganan.
Tapi kami bukan g * coders luar. Mari kita lakukan segalanya sesuai dengan kanon:
var EventUtil = { addHandler: function (elem, type, handler) { if (elem.addEventListener) { elem.addEventListener(type, handler, false) } else if (elem.attachEvent) { elem.attachEvent("on" + type, handler) } else { elem["on" = type] = hendler } }, removeHandler: function (elem, type, handler) { if (elem.removeEventListener) { elem.removeEventListener(type, handler, false) } else if (elem.detachEvent) { elem.detachEvent("on" + type, handler) } else { elem["on" = type] = null } } }
Sangat bagus, tapi bagaimana dengan objek acara? Lagi pula, di IE tidak ada .target .srcElement, preventDefault? tidak ada returnValue = false. Tetapi tidak ada yang bisa ditambahkan beberapa metode:
var EventUtil = { addHandler: function (elem, type, handler) { if (elem.addEventListener) { elem.addEventListener(type, handler, false) } else if (elem.attachEvent) { elem.attachEvent("on" + type, handler) } else { elem["on" = type] = hendler } }, getEvent: function (event) { return event ? event : window.event }, getTarget: function (event) { return event.target || event.srcElement }, preventDefault: function (event) { if (event.preventDefault) { event.preventDefault() } else { event.returnValue = false } }, removeHandler: function (elem, type, handler) { if (elem.removeEventListener) { elem.removeEventListener(type, handler, false) } else if (elem.detachEvent) { elem.detachEvent("on" + type, handler) } else { elem["on" = type] = null } }, stopPropagation: function (event) { if (event.stopPropagation) { event.stopPropagation() } else { event.cancelBubble = true } } }
Dll dll. dan ini semua tarian.
Ya, kita sudah selesai, kita menyelesaikan semua masalah, semuanya baik-baik saja. Benar, kode keluar agak rumit. Sekarang bayangkan kita membutuhkan banyak langganan untuk banyak elemen. Wow, ini akan mengambil beberapa baris kode. Contoh:
<ul> <li id="id1">go somewhere</li> <li id="id2">do something</li> <li id="some-next-id">next</li> </ul> var item1 = document.getElementById('id1') var item2 = document.getElementById('id2') var itemNext = document.getElementById('some-next-id') EventUtil.addHandler(item1, "click", someHandle) EventUtil.addHandler(item2, "click", someHandle2) EventUtil.addHandler(itemNext, "click", someHandle3)
Dan untuk setiap elemen, dan kita tidak boleh lupa untuk menghapus, bekerja dengan target dan sejenisnya
Dan di sini delegasi acara datang untuk membantu kami.
Yang perlu kita lakukan adalah menghubungkan satu handler tunggal ke titik tertinggi di pohon DOM:
<ul id="main-id">
Akibatnya, kami hanya memiliki satu penangan dalam memori, dan properti id dapat digunakan untuk tindakan yang diinginkan. Konsumsi memori yang lebih sedikit meningkatkan kinerja halaman secara keseluruhan. Mendaftarkan pengendali acara membutuhkan lebih sedikit waktu dan lebih sedikit panggilan ke DOM. Pengecualiannya mungkin mouseover dan mouseout, dengan mereka semuanya sedikit lebih rumit.
Sekarang bagaimana dengan Bereaksi
Segala sesuatu tentang kompatibilitas lintas-browser untuk kami telah dilakukan oleh orang-orang dari facebook. Semua penangan acara kami menerima instance dari SyntheticEvent . Yang menangani kami menggunakan kembali acara dari kolam renang, menghapus semua properti setelah memanggil pawang.
Bagus
Namun demikian, penangan ekstra adalah penangan ekstra. Saya bertemu beberapa kali, dan saya bertobat, saya menulis kode seperti ini:
class Example extends React.Component { handleClick () { console.log('click') } render () { return ( <div> {new Array(20).fill().map((_, index) => <div key={index} // elem.id id={index} // elem.id onClick={() => console.log('click')} /> )} </div> ) } }
Contoh menunjukkan kasus ketika ada beberapa jenis sheet dengan n-number elemen, dan karenanya dengan n-number registrasi handler.
Mari kita jalankan, buka halaman dan periksa berapa banyak penangan yang sedang beraksi saat ini. Untuk ini, saya menemukan skrip yang bagus:
Array.from(document.querySelectorAll('*')) .reduce(function(pre, dom){ var clks = getEventListeners(dom).click; pre += clks ? clks.length || 0 : 0; return pre }, 0)
Bekerja di perangkat dev chrome.
Dan sekarang kami mendelegasikan semua ini ke div induk dan sorak-sorai, kami hanya mengoptimalkan aplikasi kami n = array.length kali. Contoh kode di bawah ini:
class Example extends React.Component { constructor () { super() this.state = { useElem: 0 } } handleClick (elem) { var id = elem.target.id this.setState({ useElem: id }) } render () { return ( <div onClick={this.handleClick}> {new Array(20).fill().map((_, index) => <div key={index} // elem.id id={index} // elem.id useElem={index === this.state.useElem} /> )} </div> ) } }
Delegasi adalah alat yang baik untuk memproses sejumlah besar langganan, dan dalam kasus rendering dinamis dan gambar ulang yang sering, itu hanya tak tergantikan. Kasihan sumber daya pengguna, mereka tidak terbatas.
Artikel ini didasarkan pada buku JavaScript untuk pengembang web profesional, yang ditulis oleh Nicholas Zakas.
Terima kasih banyak atas perhatiannya. Jika Anda memiliki sesuatu untuk dibagikan atau menemukan beberapa kekurangan, mungkin kesalahan atau hanya punya pertanyaan, kemudian tulis di komentar. Saya akan dengan senang hati menerima umpan balik!