Cara cepat memulai VUE3.0: Memulai
Dalam tutorial ini, kita akan mempelajari cara mengimplementasikan Memoization di React. Memoisasi meningkatkan kinerja dengan menyimpan hasil pemanggilan fungsi dalam cache dan mengembalikan hasil cache tersebut saat diperlukan lagi.
Kita akan membahas hal berikut:
Artikel ini mengasumsikan Anda memiliki pemahaman dasar tentang komponen kelas dan fungsi di React.
Jika Anda ingin melihat topik ini, Anda dapat melihat dokumentasi resmi komponen dan props React
https://reactjs.org/docs/components-and-props.html
Sebelum membahas detail Memoisasi di React, mari kita lihat dulu bagaimana React menggunakan DOM virtual untuk merender UI.
DOM biasa pada dasarnya berisi sekumpulan node yang disimpan dalam bentuk pohon. Setiap node di DOM mewakili elemen UI. Setiap kali terjadi perubahan status dalam aplikasi, node terkait untuk elemen UI tersebut dan semua elemen turunannya diperbarui di pohon DOM, yang kemudian memicu penggambaran ulang UI.
Dengan bantuan algoritme pohon DOM yang efisien, pembaruan node menjadi lebih cepat, namun menggambar ulang menjadi lambat dan dapat memengaruhi performa ketika DOM memiliki sejumlah besar elemen UI. Oleh karena itu, DOM virtual diperkenalkan di React.
Ini adalah representasi virtual dari DOM sebenarnya. Sekarang, setiap kali ada perubahan pada status aplikasi, React tidak memperbarui DOM asli secara langsung, namun membuat DOM virtual baru. React kemudian akan membandingkan DOM virtual baru ini dengan DOM virtual yang dibuat sebelumnya, menemukan perbedaannya (Catatan Penerjemah: yaitu, menemukan node yang perlu diperbarui), dan kemudian menggambar ulang.
Berdasarkan perbedaan ini, DOM virtual dapat memperbarui DOM asli dengan lebih efisien. Hal ini meningkatkan kinerja karena DOM virtual tidak hanya memperbarui elemen UI dan semua elemen turunannya, namun secara efektif hanya memperbarui perubahan yang diperlukan dan minimal pada DOM sebenarnya.
Di bagian sebelumnya, kita melihat bagaimana React menggunakan DOM virtual untuk melakukan operasi pembaruan DOM secara efisien guna meningkatkan kinerja. Di bagian ini, kami akan memperkenalkan contoh yang menjelaskan perlunya menggunakan Memoisasi untuk lebih meningkatkan kinerja.
Kita akan membuat kelas induk yang berisi tombol yang menambah variabel bernama count
. Komponen induk juga memanggil komponen anak dan meneruskan parameter ke komponen tersebut. Kami juga menambahkan pernyataan console.log()
dalam metode render
:
//Parent.js kelas Induk memperluas React.Component { konstruktor(alat peraga) { super(alat peraga); this.state = { hitungan: 0 }; } menanganiKlik = () => { ini.setState((prevState) => { return { hitungan: prevState.count + 1 }; }); }; memberikan() { console.log("Render induk"); kembali ( <div className="Aplikasi"> <button onClick={this.handleClick}>Peningkatan</button> <h2>{ini.negara bagian.hitungan</h2> <Nama anak={"joe"} /> </div> ); } } ekspor default Induk;
Kode lengkap untuk contoh ini dapat dilihat di CodeSandbox.
Kita akan membuat kelas Child
yang menerima parameter yang diteruskan oleh komponen induk dan menampilkannya di UI:
//Child.js kelas Anak memperluas React.Component { memberikan() { console.log("Render anak"); kembali ( <div> <h2>{ini.props.nama</h2> </div> ); } } ekspor default Anak;
Nilai count
akan berubah setiap kali kita mengklik tombol di komponen induk. Karena status telah berubah, metode render
dari komponen induk dijalankan.
Parameter yang diteruskan ke komponen anak tidak berubah setiap kali komponen induk dirender ulang, sehingga komponen anak tidak boleh dirender ulang. Namun, ketika kita menjalankan kode di atas dan terus menambah count
, kita mendapatkan output berikut:
Render induk Render anak Render orang tua Render anak Render orang tua Render anak
Anda dapat mencoba contoh di atas di kotak pasir ini dan melihat keluaran konsol.
Dari outputnya, kita dapat melihat bahwa ketika komponen induk dirender ulang, komponen anak akan dirender ulang meskipun parameter yang diteruskan ke komponen anak tetap tidak berubah. Hal ini akan menyebabkan DOM virtual komponen anak melakukan pemeriksaan berbeda terhadap DOM virtual sebelumnya. Karena tidak ada perubahan pada komponen turunan kita dan semua props tidak berubah saat rendering ulang, DOM asli tidak akan diperbarui.
Ini jelas merupakan keuntungan kinerja karena DOM asli tidak diperbarui jika tidak perlu, namun kita dapat melihat bahwa DOM virtual baru dibuat dan pemeriksaan diff dilakukan bahkan ketika tidak ada perubahan aktual pada komponen turunan. Untuk komponen React yang kecil, biaya kinerja ini dapat diabaikan, namun untuk komponen besar, dampak kinerjanya bisa signifikan. Untuk menghindari rendering ulang dan pemeriksaan diferensial DOM virtual, kami menggunakan Memoisasi.
Dalam konteks aplikasi React, Memoisasi adalah suatu cara dimana setiap kali komponen induk dirender ulang, komponen anak hanya dirender ulang ketika props bergantung pada perubahan. Jika tidak ada perubahan pada props yang bergantung pada komponen anak, maka metode render tidak akan dijalankan dan akan mengembalikan hasil cache. Karena metode render tidak dijalankan, tidak akan ada pembuatan DOM virtual dan pemeriksaan diferensial, sehingga menghasilkan peningkatan kinerja.
Sekarang, mari kita lihat bagaimana mengimplementasikan Memoisasi di komponen kelas dan fungsi untuk menghindari rendering ulang yang tidak perlu ini.
Untuk mengimplementasikan Memoisasi pada komponen kelas, kita akan menggunakan React.PureComponent. React.PureComponent
mengimplementasikan seharusnyaComponentUpdate(), yang melakukan perbandingan dangkal state
dan props
dan hanya merender ulang komponen React jika props atau state berubah.
Ubah komponen anak menjadi kode seperti ini:
//Child.js class Child extends React.PureComponent { // Di sini kita mengubah React.Component menjadi React.PureComponent memberikan() { console.log("Render anak"); kembali ( <div> <h2>{ini.props.nama</h2> </div> ); } } ekspor default Anak;
Kode lengkap untuk contoh ini ditampilkan di kotak pasir ini.
Komponen induknya tetap tidak berubah. Sekarang, ketika kita menambah count
komponen induk, output di konsol akan terlihat seperti ini:
Render induk Render anak Render orang tua Render induk
Untuk rendering pertama, ia memanggil metode render
dari komponen induk dan komponen anak.
Untuk setiap rendering ulang setelah peningkatan count
, hanya fungsi render
dari komponen induk yang dipanggil. Komponen anak tidak akan dirender ulang.
Untuk mengimplementasikan Memoisasi pada Komponen Fungsi, kita akan menggunakan React.memo(). React.memo()
adalah komponen tingkat tinggi (HOC) yang melakukan pekerjaan serupa dengan PureComponent
untuk menghindari rendering ulang yang tidak perlu.
Berikut kode untuk komponen fungsi:
//Child.js fungsi ekspor Anak(alat peraga) { console.log("Render anak"); kembali ( <div> <h2>{props.name}</h2> </div> ); } ekspor default React.memo(Child); // Di sini kita menambahkan HOC ke komponen anak untuk mengimplementasikan Memoisasi
dan juga mengubah komponen induk menjadi komponen fungsi, seperti yang ditunjukkan di bawah ini:
//Parent.js ekspor fungsi default Induk() { const [hitungan, setCount] = useState(0); const handleKlik = () => { setCount(hitungan + 1); }; console.log("Render induk"); kembali ( <div> <button onClick={handleClick}>Peningkatan</button> <h2>{hitung}</h2> <Nama anak={"joe"} /> </div> ); }
Kode lengkap untuk contoh ini dapat dilihat di sandbox ini.
Sekarang, saat kita menambah count
komponen induk, output berikut akan ditampilkan di konsol:
Render induk Render anak Render orang tua Render orang tua
Parent renderReact.memo()
Pada contoh di atas, kita melihat bahwa ketika kita menggunakan React.memo()
HOC pada komponen anak, komponen anak tidak dirender ulang meskipun komponen induk dirender ulang.
Namun, satu hal kecil yang perlu diperhatikan adalah jika kita meneruskan fungsi sebagai parameter ke komponen anak, komponen anak tersebut akan dirender ulang bahkan setelah menggunakan React.memo()
. Mari kita lihat contohnya.
Kami akan mengubah komponen induk seperti yang ditunjukkan di bawah ini. Di sini kita menambahkan fungsi handler dan meneruskannya sebagai parameter ke komponen anak:
//Parent.js ekspor fungsi default Induk() { const [hitungan, setCount] = useState(0); const handleKlik = () => { setCount(hitungan + 1); }; pengendali const = () => { console.log("handler"); // Fungsi handler di sini akan diteruskan ke komponen anak}; console.log("Render induk"); kembali ( <div className="Aplikasi"> <button onClick={handleClick}>Peningkatan</button> <h2>{hitung}</h2> <Nama anak={"joe"} childFunc={handler} /> </div> ); }
Kode komponen anak akan tetap seperti apa adanya. Kami tidak akan menggunakan fungsi yang diteruskan dari komponen induk ke komponen anak:
//Child.js fungsi ekspor Anak(alat peraga) { console.log("Render anak"); kembali ( <div> <h2>{props.name}</h2> </div> ); } ekspor default React.memo(Child);
Sekarang ketika kita menambah count
komponen induk, ia akan merender ulang dan merender ulang komponen anak pada saat yang sama meskipun tidak ada perubahan pada parameter yang diteruskan.
Jadi, apa yang menyebabkan subkomponen dirender ulang? Jawabannya adalah setiap kali komponen induk dirender ulang, fungsi handler
baru dibuat dan diteruskan ke komponen anak. Sekarang, karena fungsi handle
dibuat ulang pada setiap rendering ulang, komponen anak akan menemukan bahwa referensi handler
telah berubah ketika melakukan perbandingan dangkal props, dan merender ulang komponen anak.
Selanjutnya, kami akan membahas cara memperbaiki masalah ini.
useCallback()
untuk menghindari perenderan ulang lebih lanjut.Masalah utama dengan perenderan ulang komponen anak adalah fungsi handler
dibuat ulang, yang mengubah referensi yang diteruskan ke komponen anak. Oleh karena itu, diperlukan cara untuk menghindari duplikasi tersebut. Jika fungsi handler
tidak dibuat ulang, referensi ke fungsi handler
tidak berubah, sehingga komponen turunan tidak dirender ulang.
Untuk menghindari keharusan membuat ulang fungsi setiap kali komponen induk dirender, kita akan menggunakan React Hook yang disebut useCallback(). Hooks diperkenalkan di React 16. Untuk mempelajari lebih lanjut tentang Hooks, Anda dapat melihat dokumentasi hooks resmi React, atau lihat `React Hooks: Bagaimana Memulai & Membangun Milik Anda".
Hook useCallback()
mengambil dua parameter: fungsi callback dan daftar dependensi
Berikut adalah contoh useCallback()
:
const handleClick = useCallback(() => {
.
//Lakukan sesuatu }, [x,y]);
Di sini, useCallback()
ditambahkan ke fungsi handleClick()
. Parameter kedua [x, y]
dapat berupa array kosong, ketergantungan tunggal, atau daftar ketergantungan. Fungsi handleClick()
hanya dibuat ulang setiap kali salah satu dependensi yang disebutkan dalam parameter kedua berubah.
Jika dependensi yang disebutkan dalam useCallback()
tidak berubah, maka versi fungsi callback Memoized yang disebutkan sebagai argumen pertama akan dikembalikan. Kita akan mengubah komponen induk untuk menggunakan kait useCallback()
pada penangan yang diteruskan ke komponen anak:
//Parent.js ekspor fungsi default Induk() { const [hitungan, setCount] = useState(0); const handleKlik = () => { setCount(hitungan + 1); }; const handler = useCallback(() => { // Gunakan useCallback() untuk fungsi handler console.log("penangan"); }, []); console.log("Render induk"); kembali ( <div className="Aplikasi"> <button onClick={handleClick}>Peningkatan</button> <h2>{hitung}</h2> <Nama anak={"joe"} childFunc={handler} /> </div> ); }
Kode komponen anak akan tetap seperti apa adanya.
Kode lengkap untuk contoh ini ada di sandbox ini.
Ketika kita menambah count
komponen induk dari kode di atas, kita dapat melihat keluaran berikut:
Render induk Render anak Render orang tua Render orang tua Render induk
Karena kita menggunakan hook useCallback()
untuk handler
di komponen induk, fungsi handler
tidak akan dibuat ulang setiap kali komponen induk dirender ulang, dan versi Memoisasi dari handler
akan diteruskan ke komponen anak. Komponen anak akan melakukan perbandingan dangkal dan memperhatikan bahwa referensi ke fungsi handler
tidak berubah, sehingga tidak akan memanggil metode render
.
Memoization adalah cara yang baik untuk menghindari rendering ulang komponen yang tidak perlu ketika status atau propsnya tidak berubah, sehingga meningkatkan kinerja aplikasi React. Anda mungkin mempertimbangkan untuk menambahkan Memoization ke semua komponen Anda, tapi itu belum tentu merupakan cara untuk membangun komponen React yang berkinerja tinggi. Memoisasi hanya boleh digunakan jika komponen:
Dalam tutorial ini kita memahami:
React.memo()
untuk komponen fungsi dan React.PureComponent
untuk komponen kelasReact.memo()
useCallback()
menghindari masalah rendering ulang ketika fungsi diteruskan sebagai props ke komponen anak.Saya harap pengenalan React Memoization ini bermanfaat bagi Anda!
Alamat asli: https://www.sitepoint.com/implement-memoization-in-react-to-improve-kinerja/Penulis asli
: Nida Khan