React Suspense: Pelajaran yang dipelajari dari pemuatan data
Ketegangan adalah ciri yang akan datang dari React yang membantu menyelaraskan operasi asynchronous seperti pemuatan data, menjadikannya mudah bagi anda untuk mengelakkan ketidakkonsistenan negara dalam UI. Saya akan menerangkan dengan lebih terperinci apa maksudnya, dan memberikan pengenalan ringkas kepada ketegangan, maka kes penggunaan yang lebih realistik dan beberapa pelajaran yang dipelajari.
Fungsi yang saya diperkenalkan masih dalam peringkat alfa dan tidak boleh digunakan dalam persekitaran pengeluaran. Siaran ini adalah untuk mereka yang ingin melihat ciri -ciri pertama yang akan datang dan memahami di mana mereka akan menuju ke masa depan.
Salah satu bahagian pembangunan aplikasi yang paling mencabar ialah menyelaraskan keadaan aplikasi dan bagaimana data dimuatkan. Perubahan negeri biasanya mencetuskan pemuatan data baru di pelbagai lokasi. Biasanya, setiap sekeping data akan mempunyai UI pemuatan sendiri (seperti "pemutar") yang kira -kira di mana data berada dalam aplikasi. Sifat pemuatan data yang tidak segerak bermakna bahawa permintaan ini dapat dikembalikan dalam apa -apa perintah. Akibatnya, bukan sahaja permohonan anda akan muncul dan hilang dengan banyak pemintal yang berbeza, tetapi lebih buruk lagi, aplikasi anda mungkin memaparkan data yang tidak konsisten. Sekiranya dua daripada tiga beban data anda selesai, anda akan melihat pemutar beban di bahagian atas kedudukan ketiga, masih menunjukkan data lama yang sudah lama sudah lama.
Saya tahu itu terlalu banyak. Sekiranya anda mendapati mana -mana mengelirukan, anda mungkin berminat dengan artikel sebelumnya mengenai ketegangan yang saya tulis. Artikel ini memperkenalkan lebih terperinci apa ketegangan dan apa yang dilaksanakannya. Perhatikan bahawa beberapa butiran kecil ini kini sudah lapuk, iaitu cangkuk useTransition
tidak lagi menerima nilai timeoutMs
, tetapi menunggu selama -lamanya.
Sekarang, mari kita lihat dengan cepat butiran dan kemudian teruskan ke kes penggunaan tertentu dengan beberapa perangkap yang mengintai.
Nasib baik, pasukan React cukup pintar untuk tidak mengehadkan usaha ini untuk hanya memuatkan data. Ketegangan berfungsi melalui primitif peringkat rendah, yang boleh anda gunakan untuk hampir apa-apa. Mari kita lihat dengan cepat pada primitif ini.
Pertama sekali<suspense></suspense>
Sempadan, ia menerima atribut fallback
:
<suspense fallback="{<Fallback"></suspense> }>
Setiap kali mana -mana komponen kanak -kanak di bawah komponen ini digantung, ia menjadikan fallback
. Tidak kira berapa banyak subkomponen digantung, atas sebab apa pun, fallback
dipaparkan. Ini adalah satu cara yang bertindak balas memastikan bahawa UI adalah konsisten - ia tidak akan menyebabkan apa -apa sehingga semuanya siap.
Tetapi apa yang berlaku apabila pengguna mengubah status dan memuat data baru selepas kandungannya pada mulanya diberikan? Kami pastinya tidak mahu UI kami yang sedia ada hilang dan menunjukkan fallback
kami; itu akan menjadi pengalaman pengguna yang buruk. Sebaliknya, kami mungkin mahu memaparkan pemutar pemuatan sehingga semua data siap sebelum UI baru dipaparkan.
Hook useTransition
melaksanakan ini. Cangkuk ini mengembalikan fungsi dan nilai boolean. Kami memanggil fungsi dan membungkus perubahan keadaan kita. Sekarang perkara semakin menarik. React cuba menerapkan perubahan status kami. Jika ada yang tergantung, React menetapkan nilai boolean kepada true
dan menunggu hang ke akhir. Setelah selesai, ia akan cuba menggunakan perubahan status lagi. Mungkin ia akan berjaya kali ini, atau mungkin sesuatu yang lain akan digantung. Bagaimanapun, bendera Boolean akan tetap true
sehingga semuanya siap, dan hanya kemudian perubahan keadaan akan diselesaikan dan dicerminkan dalam UI.
Akhirnya, bagaimana kita menggantung? Kami menggantung dengan melemparkan janji. Jika data diminta dan kita perlu mengambil, maka kita mengambil - dan membuang janji yang berkaitan dengan pengambilan itu. Mekanisme penggantungan peringkat rendah ini bermakna kita boleh menggunakannya untuk apa-apa. Utiliti React.lazy
untuk komponen pemuatan malas sudah berfungsi dengan ketegangan, dan saya telah menulis sebelum menggunakan ketegangan untuk menunggu imej dimuatkan sebelum memaparkan UI untuk mengelakkan kandungan bergerak.
Jangan risau, kami akan membincangkan semua ini.
Kami akan membina sesuatu yang sedikit berbeza dari contoh -contoh dalam artikel lain yang serupa. Ingat bahawa ketegangan masih dalam fasa alfa, jadi utiliti data pemuatan kegemaran anda mungkin tidak mempunyai sokongan ketegangan lagi. Tetapi itu tidak bermakna kita tidak boleh menipu sesuatu dan memahami bagaimana ketegangan berfungsi.
Mari kita bina senarai pemuatan tak terhingga yang memaparkan beberapa data dan menggabungkan beberapa imej yang dimuatkan berdasarkan ketegangan. Kami akan memaparkan data kami, serta butang untuk memuat lebih banyak data. Apabila data diberikan, kami akan memuatkan imej yang berkaitan dan menggantung sebelum ia siap.
Kes penggunaan ini berdasarkan kerja sebenar yang saya lakukan di projek sampingan saya (sekali lagi, jangan gunakan ketegangan dalam pengeluaran-tetapi projek sampingan dibenarkan). Saya menggunakan klien GraphQL saya sendiri pada masa itu dan motivasi untuk jawatan ini adalah beberapa kesukaran yang saya ada. Untuk memudahkan operasi dan memberi tumpuan kepada ketegangan itu sendiri, dan bukannya mana -mana utiliti pemuatan data tunggal, kami hanya akan menjalin pemuatan data.
Ini adalah kotak pasir yang kami cuba pada mulanya. Kami akan menggunakannya untuk menerangkan segala langkah demi langkah, jadi tidak perlu tergesa -gesa untuk memahami semua kod sekarang.
Komponen App
root kami menjadikan sempadan ketegangan seperti ini:
<suspense fallback="{<Fallback"></suspense> }>
fallback
membuat apabila apa -apa hang (kecuali perubahan keadaan berlaku dalam panggilan useTransition
). Untuk membuat perkara lebih mudah difahami, saya membuat komponen Fallback
ini menjadikan keseluruhan UI merah jambu, jadi sukar untuk dilewatkan;
Kami memuatkan blok data semasa di dalam komponen DataList
:
const newData = useQuery (param);
Hook useQuery
kami adalah keras untuk mengembalikan data palsu, termasuk masa tamat untuk permintaan rangkaian simulasi. Ia mengendalikan hasil cache dan melemparkan janji jika data tidak di -cache.
Kami menyimpan status (sekurang -kurangnya buat masa ini) dalam senarai data utama yang kami paparkan:
const [data, setData] = useState ([]);
Apabila data baru diluluskan dari cangkuk kami, kami memasukkannya ke senarai utama kami:
useeffect (() => { setData ((d) => d.concat (newData)); }, [newdata]);
Akhirnya, apabila pengguna memerlukan lebih banyak data, mereka mengklik butang, yang memanggil fungsi ini:
fungsi loadmore () { startTransition (() => { setParam ((x) => x 1); }); }
Akhirnya, ambil perhatian bahawa saya menggunakan komponen SuspenseImg
untuk mengendalikan preload imej yang saya paparkan dengan setiap data. Hanya lima imej rawak yang dipaparkan, tetapi saya menambah rentetan pertanyaan untuk memastikan beban baru dibuat untuk setiap sekeping data baru yang kita hadapi.
Untuk meringkaskan di mana kami berada di sekarang, kami mempunyai cangkuk yang memuat data semasa. Cangkuk ini mengikuti mekanisme ketegangan dan melemparkan janji apabila memuatkan. Apabila data berubah, jumlah senarai projek berjalan dikemas kini dan projek baru dilampirkan. Ini berlaku dalam useEffect
. Setiap projek menjadikan imej, kami menggunakan komponen SuspenseImg
untuk memasak imej dan menggantung sebelum ia siap. Sekiranya anda ingin tahu bagaimana beberapa kod berfungsi, lihat catatan saya sebelum ini mengenai imej preloading dengan ketegangan.
Jika semuanya berfungsi dengan baik, ini akan menjadi catatan blog yang sangat membosankan, jangan risau, itu tidak normal. Ambil perhatian bahawa skrin fallback
merah jambu akan dipaparkan dan kemudian dengan cepat tersembunyi pada beban awal, tetapi kemudiannya akan dipaparkan semula.
Apabila kita mengklik butang untuk memuatkan lebih banyak data, kita melihat penunjuk beban sebaris (dikawal oleh cangkuk useTransition
) flip ke true
. Kemudian kita melihatnya flip ke false
, dan paparan merah fallback
asal kita. Kami menjangkakan bahawa skrin merah jambu tidak lagi melihat selepas beban awal; Apa yang berlaku?
Ia telah tersembunyi di tempat yang mudah dilihat:
useeffect (() => { setData ((d) => d.concat (newData)); }, [newdata]);
useEffect
berjalan apabila perubahan keadaan selesai, iaitu perubahan keadaan telah digantung dan digunakan untuk DOM. Bahagian itu, "selesai menunggu" adalah kunci di sini. Kita boleh menetapkan keadaan di sini jika kita mahu, tetapi jika perubahan keadaan itu hang lagi, ia adalah hang baru. Inilah sebabnya mengapa kita melihat merah jambu berkelip selepas beban awal dan pemuatan data berikutnya. Dalam kedua -dua kes, pemuatan data dilakukan, dan kemudian kami menetapkan keadaan dalam satu kesan, yang menyebabkan data baru benar -benar membuat dan menggantung semula kerana imej itu dimuatkan.
Jadi, bagaimana kita menyelesaikan masalah ini? Pada satu tahap, penyelesaiannya adalah mudah: Berhenti menetapkan keadaan dalam kesannya. Tetapi ini lebih mudah dikatakan daripada dilakukan. Bagaimanakah kita mengemas kini senarai penyertaan berjalan untuk melampirkan hasil baru tanpa menggunakan kesan? Anda mungkin fikir kita boleh menggunakan ref untuk menjejaki perkara.
Malangnya, ketegangan membawa beberapa peraturan baru mengenai ref, iaitu, kita tidak boleh menetapkan ref di dalam render. Jika anda tertanya -tanya mengapa, ingat bahawa ketegangan adalah semua tentang React cuba untuk menjalankan render, melihat janji yang dilemparkan, dan kemudian membuang yang menyebabkan separuh jalan. Sekiranya kita menukar ref sebelum rendering dibatalkan dan dibuang, ref masih mempunyai perubahan itu, tetapi mempunyai nilai yang tidak sah. Fungsi rendering perlu murni dan tidak mempunyai kesan sampingan. Ini selalu menjadi peraturan untuk React, tetapi kini lebih penting lagi.
Inilah penyelesaiannya, kami akan menerangkan perenggan dengan perenggan.
Pertama, bukannya menyimpan senarai data utama kami di Negeri, lakukan sesuatu yang berbeza: Mari simpan senarai halaman yang kita lihat. Kami boleh menyimpan halaman paling terkini di ref (walaupun kami tidak akan menulisnya dalam render) dan menyimpan pelbagai halaman yang dimuatkan di negeri ini.
const currentPage = useref (0); const [halaman, setPages] = useState ([currentPage.current]);
Untuk memuat lebih banyak data, kami akan mengemas kini dengan sewajarnya:
fungsi loadmore () { startTransition (() => { currentPage.current = currentPage.Current 1; setPages ((halaman) => pages.concat (currentPage.current)); }); }
Walau bagaimanapun, bahagian yang rumit adalah cara menukar nombor halaman ini ke dalam data sebenar. Apa yang tidak boleh kita lakukan adalah gelung melalui halaman ini dan panggil cangkuk useQuery
kami; Kami memerlukan API data berasaskan baru. Menurut konvensyen yang sangat tidak rasmi yang saya lihat dalam demo ketegangan masa lalu saya, saya menamakan kaedah ini read()
. Ia tidak akan menjadi cangkuk. Sekiranya data di -cache, ia mengembalikan data yang diminta, jika tidak, janji akan dibuang. Untuk cangkuk pemuatan data kami, tidak perlu membuat perubahan sebenar; Tetapi untuk perpustakaan utiliti pemuatan data sebenar, ia mungkin mengambil beberapa kerja untuk penulis untuk mendedahkan kedua -dua pilihan sebagai sebahagian daripada API awam mereka. Dalam klien GraphQL yang saya nyatakan sebelum ini, memang ada kedua -dua Kaedah useSuspenseQuery
dan kaedah read()
pada objek klien.
Dengan kaedah read()
baru ini, bahagian terakhir kod kami adalah remeh:
const data = pages.flatmap ((halaman) => baca (halaman));
Kami mengambil setiap halaman dan meminta data yang sepadan menggunakan kaedah read()
kami. Jika mana -mana halaman tidak di -cache (ia sepatutnya hanya halaman terakhir dalam senarai), janji akan dibuang dan bertindak balas akan digantung untuk kami. Apabila Janji Parses, React akan mencuba perubahan keadaan sebelumnya sekali lagi, dan kod ini akan dijalankan semula.
Jangan biarkan panggilan flatMap
mengelirukan anda. Ia adalah perkara yang sama seperti yang dilakukan oleh map
, kecuali ia mendapat setiap hasil dalam array baru dan "meratakan" jika ia sendiri adalah array.
Dengan perubahan ini, apabila kita mula, semuanya berfungsi seperti yang diharapkan. Skrin pemuatan merah jambu kami dipaparkan sekali pada beban awal, dan kemudian dalam beban berikutnya, status pemuatan sebaris dipaparkan sehingga semuanya siap.
Ketegangan adalah kemas kini yang menarik untuk bertindak balas. Ia masih dalam fasa alfa, jadi jangan cuba menggunakannya untuk apa -apa yang penting. Tetapi jika anda adalah jenis pemaju yang suka mendapatkan yang pertama untuk mengalami kandungan yang akan datang, maka saya berharap jawatan ini memberikan anda latar belakang dan maklumat yang berguna yang akan berguna apabila diterbitkan.
Atas ialah kandungan terperinci React Suspense: Pelajaran yang dipelajari semasa memuatkan data. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!