Rumah >hujung hadapan web >tutorial js >Soalan Existential React dan Dialog Modal yang sempurna
Pada pendapat anda, apakah perkara yang paling rumit dalam React? Dipaparkan semula? Konteks? Portal? Keselarasan?
Tidak.
Bahagian paling sukar dalam React ialah segalanya bukan React di sekelilingnya. Jawapan kepada soalan "Bagaimanakah perkara yang disenaraikan di atas berfungsi?" adalah mudah: ia hanya perlu mengikut algoritma dan mengambil nota. Hasilnya adalah muktamad dan sentiasa sama (jika anda mengesannya dengan betul). Ia hanya sains dan fakta.
Tetapi bagaimana pula dengan "Apakah yang menjadikan komponen baik?" atau "Apakah cara yang betul untuk melaksanakan... (sesuatu)?" atau pun "Perlukah saya menggunakan perpustakaan atau membina penyelesaian saya sendiri?" Satu-satunya jawapan yang betul di sini ialah "Ia bergantung." Kebetulan ia adalah yang paling kurang membantu.
Saya ingin mencari sesuatu yang lebih baik daripada ini untuk artikel baharu. Tetapi oleh kerana tidak ada jawapan mudah dan penyelesaian universal untuk jenis soalan tersebut, artikel itu ternyata lebih kepada panduan proses pemikiran saya dan bukannya "inilah jawapannya, lakukan selalu." Semoga masih bermanfaat.
Jadi, apakah yang diperlukan untuk mengalihkan ciri daripada idea kepada penyelesaian sedia pengeluaran? Mari cuba laksanakan Dialog Modal yang mudah dan lihat. Apa yang mungkin rumit tentang yang itu? ?
Mari kita mulakan dengan apa yang kadangkala dikenali sebagai "spike" - pelaksanaan paling mudah yang boleh membantu meneroka penyelesaian yang berpotensi dan mengumpulkan keperluan selanjutnya. Saya tahu bahawa saya sedang melaksanakan dialog modal. Andaikan saya mempunyai reka bentuk yang cantik seperti ini:
Dialog pada asasnya ialah elemen pada skrin yang muncul apabila sesuatu seperti butang diklik. Jadi di situlah saya akan mulakan.
export default function Page() { const [isOpen, setIsOpen] = useState(false); return ( <> <button onClick={() => setIsOpen(true)}> Click me </button> {isOpen ? ( <div className="dialog">some content</div> ) : null} </> ); }
Nyatakan, butang yang mendengar klik dan dialog masa hadapan yang ditunjukkan apabila keadaan itu benar. Dialog juga sepatutnya mempunyai tindakan "dekat":
<button className="close-button" onClick={() => setIsOpen(false)} > Close </button>
Ia juga mempunyai "tirai latar" - div separa lutsinar boleh klik yang menindih kandungan dan mencetuskan kehilangan modal apabila diklik.
<div className="backdrop" onClick={() => setIsOpen(false)} ></div>
Semua bersama:
export default function Page() { const [isOpen, setIsOpen] = useState(false); return ( <> <button onClick={() => setIsOpen(true)}> Click me </button> {isOpen ? ( <> <div className="backdrop" onClick={() => setIsOpen(false)} ></div> <div className="dialog"> <button className="close-button" onClick={() => setIsOpen(false)} > Close </button> </div> </> ) : null} </> ); }
Saya juga biasanya menambah gaya yang baik sejak awal. Melihat ciri yang saya laksanakan muncul pada skrin dengan rupa yang sama seperti yang sepatutnya membantu saya berfikir. Selain itu, ia boleh memaklumkan reka letak ciri, iaitu perkara yang akan berlaku dengan dialog ini.
Mari cepat tambah CSS untuk tirai latar - ini bukan sesuatu yang istimewa, hanya latar belakang separa telus pada div dengan kedudukan: tetap yang mengambil keseluruhan skrin:
export default function Page() { const [isOpen, setIsOpen] = useState(false); return ( <> <button onClick={() => setIsOpen(true)}> Click me </button> {isOpen ? ( <div className="dialog">some content</div> ) : null} </> ); }
Dialog lebih menarik sedikit kerana ia perlu diletakkan di tengah-tengah skrin. Terdapat 1001 cara untuk mencapainya dalam CSS, sudah tentu, tetapi kegemaran saya dan mungkin yang paling mudah ialah ini:
<button className="close-button" onClick={() => setIsOpen(false)} > Close </button>
Kami menggunakan kedudukan "tetap" untuk melepaskan diri daripada kekangan susun atur, menambah 50% kiri dan atas untuk mengalihkan div di tengah-ish dan mengubahnya kembali sebanyak 50%. Bahagian kiri dan atas akan dikira secara relatif kepada skrin, dan perubahan akan relatif kepada lebar/tinggi div itu sendiri, jadi hasilnya, ia akan muncul betul-betul di tengah tanpa mengira lebar atau lebar skrinnya.
Bit terakhir CSS dalam langkah ini ialah untuk menggayakan dialog itu sendiri dan butang "tutup" dengan betul. Tidak akan menyalin-tampalnya di sini, gaya sebenar tidak begitu penting, cuma lihat contoh:
Sekarang saya mempunyai pelaksanaan kasar ciri itu, tiba masanya untuk menjadikannya "nyata". Untuk melakukan itu, kita perlu memahami secara terperinci apa sebenarnya yang kita cuba selesaikan di sini dan untuk siapa. Dari segi teknikal, kita harus faham bahawa sebelum mengekodkan apa-apa, jadi selalunya, langkah ini sepatutnya Langkah 1.
Adakah dialog ini sebahagian daripada prototaip yang perlu dilaksanakan secepat mungkin, ditunjukkan kepada pelabur sekali dan tidak pernah digunakan lagi? Atau mungkin ia adalah sebahagian daripada perpustakaan generik yang anda akan terbitkan di npm dan sumber terbuka? Atau mungkin ia sebahagian daripada sistem reka bentuk yang akan digunakan oleh 5,000 orang organisasi anda? Atau adakah ia sebahagian daripada alatan dalaman untuk pasukan 3 orang kecil anda dan tiada yang lain? Atau mungkin anda bekerja untuk sesuatu seperti TikTok, dan dialog ini akan menjadi sebahagian daripada apl web yang tersedia pada mudah alih sahaja? Atau mungkin anda bekerja untuk agensi yang menulis apl untuk kerajaan sahaja?
Menjawab soalan tersebut menetapkan hala tuju perkara yang perlu dilakukan seterusnya apabila melibatkan pengekodan.
Jika ia hanya prototaip untuk digunakan sekali, ia mungkin sudah cukup bagus.
Jika ia akan menjadi sumber terbuka sebagai sebahagian daripada perpustakaan, ia perlu mempunyai API tujuan am yang sangat baik yang boleh digunakan dan difahami oleh mana-mana pembangun di dunia, banyak ujian dan dokumentasi yang baik.
Dialog yang merupakan sebahagian daripada sistem reka bentuk org 5,000 orang perlu mematuhi garis panduan reka bentuk organisasi dan mungkin dihadkan dalam kebergantungan luaran yang dibawa ke dalam repo. Jadi, anda mungkin perlu melaksanakan banyak perkara dari awal daripada melakukan npm install new-fancy-tool.
Dialog agensi yang membina untuk kerajaan mungkin perlu menjadi dialog yang paling mudah diakses dan mematuhi peraturan di alam semesta. Jika tidak, agensi itu mungkin kehilangan kontrak kerajaan dan muflis.
Dan seterusnya dan seterusnya.
Untuk tujuan artikel ini, mari kita anggap bahawa dialog itu adalah sebahagian daripada reka bentuk semula tapak web komersil besar sedia ada yang baharu dan sedang dalam proses dengan beribu-ribu pengguna dari seluruh dunia setiap hari. Reka bentuk semula sedang berjalan sehingga satu-satunya reka bentuk dengan dialog yang saya dapat ialah ini:
Selebihnya akan datang kemudian, pereka-perekanya sudah berlambak. Selain itu, saya adalah sebahagian daripada pasukan tetap yang melakukan reka bentuk semula dan menyelenggara tapak web pada masa hadapan, bukan kontraktor luar yang diupah untuk satu projek.
Dalam kes ini, hanya mempunyai gambar ini dan mengetahui tentang matlamat syarikat kami memberi saya maklumat yang mencukupi untuk membuat andaian munasabah dan melaksanakan 90% dialog. Selebihnya 10% boleh diperhalusi kemudian.
Itu adalah andaian yang boleh saya buat berdasarkan maklumat di atas:
Tapak web sedia ada mempunyai ribuan pengguna setiap hari dari seluruh dunia, jadi saya perlu memastikan dialog, sekurang-kurangnya, berfungsi pada kedua-dua skrin besar dan mudah alih, serta penyemak imbas yang berbeza. Sebaik-baiknya, saya perlu menyemak analitis sedia ada untuk mendapatkan kepastian sepenuhnya, tetapi ini adalah pertaruhan yang agak selamat.
Lebih daripada seorang pembangun sedang menulis kod untuk ini, dan kod itu akan kekal. Laman web ini besar dan sudah mempunyai ribuan pengguna; ia bukan prototaip pantas untuk pelabur. Jadi, saya perlu memastikan bahawa kod itu boleh dibaca, API masuk akal, ia boleh digunakan dan diselenggara, dan ia tidak mempunyai senjata kaki yang jelas.
Syarikat mengambil berat tentang imej dan kualiti tapak webnya - jika tidak, mengapa mereka akan melakukan reka bentuk semula sama sekali? (Mari kita anggap niat positif di sini?). Ini bermakna tahap kualiti tertentu dijangka, dan saya perlu berfikir ke hadapan dan menjangka senario biasa dan kes kelebihan, walaupun ia belum lagi sebahagian daripada reka bentuk semasa.
Ramai pengguna berkemungkinan bermaksud bahawa tidak semua daripada mereka secara eksklusif menggunakan tetikus untuk berinteraksi dengan tapak web. Dialog juga mesti tersedia melalui interaksi papan kekunci dan mungkin juga teknologi bantuan seperti pembaca skrin.
Pangkalan kod sedia ada yang besar (ia reka bentuk semula, ingat!) bermakna terdapat kemungkinan sekatan pada kebergantungan luaran yang boleh saya bawa untuk ciri ini. Sebarang pergantungan luar datang dengan kos, terutamanya dalam pangkalan kod yang besar dan lama. Untuk tujuan artikel, mari kita anggap bahawa saya boleh menggunakan perpustakaan luaran, tetapi saya perlu mempunyai rasional yang baik untuk ini.
Akhirnya, lebih banyak reka bentuk akan datang, jadi saya perlu menjangka ke arah mana ia boleh pergi dari reka bentuk dan sudut pandangan pengguna dan pastikan kod itu boleh mengendalikannya lebih awal.
Sekarang saya tahu keperluan dan mempunyai tekaan yang munasabah, saya boleh membuat komponen dialog sebenar. Pertama sekali, daripada kod ini:
export default function Page() { const [isOpen, setIsOpen] = useState(false); return ( <> <button onClick={() => setIsOpen(true)}> Click me </button> {isOpen ? ( <div className="dialog">some content</div> ) : null} </> ); }
Saya benar-benar perlu mengekstrak bahagian dialog ke dalam komponen boleh guna semula - akan ada banyak ciri berasaskan dialog untuk dilaksanakan.
<button className="close-button" onClick={() => setIsOpen(false)} > Close </button>
Dialog akan mempunyai prop onClose - ia akan memberitahu komponen induk apabila butang "tutup" atau tirai latar diklik. Komponen induk kemudiannya masih mempunyai keadaan dan memaparkan dialog seperti ini:
<div className="backdrop" onClick={() => setIsOpen(false)} ></div>
Sekarang, mari lihat reka bentuk sekali lagi dan fikirkan tentang dialog lagi:
Jelas akan terdapat beberapa bahagian "pengaki" dialog dengan butang tindakan. Kemungkinan besar terdapat banyak variasi butang tersebut - satu, dua, tiga, dijajarkan ke kiri, kanan, dengan ruang di antaranya, dsb. Selain itu, dialog ini tidak mempunyai pengepala, tetapi kemungkinan besar ia mungkin ada - dialog dengan beberapa pengepala adalah corak yang agak biasa. Pasti akan ada kawasan kandungan di sini dengan kandungan rawak sepenuhnya - daripada hanya teks pengesahan kepada borang kepada pengalaman interaktif kepada teks boleh tatal "terma dan syarat" yang sangat panjang yang tiada siapa yang membaca.
Akhir sekali, saiz. Dialog dalam reka bentuk adalah kecil, hanya dialog pengesahan. Borang besar atau teks panjang tidak akan muat di sana. Jadi, memandangkan maklumat yang kami kumpulkan dalam Langkah 2, agak selamat untuk mengandaikan bahawa saiz dialog perlu diubah. Pada masa ini, memandangkan pereka bentuk berkemungkinan mempunyai garis panduan reka bentuk, kami boleh mengandaikan bahawa kami akan mempunyai tiga variasi dialog: "kecil", "sederhana" dan "besar".
Semua ini bermakna kita perlu mempunyai prop pada ModalDialog: pengaki dan pengepala akan menjadi prop biasa sahaja yang menerima ReactNode, saiz akan menjadi satu kesatuan rentetan, dan kawasan kandungan, sebagai bahagian utama, akan masuk ke kanak-kanak:
export default function Page() { const [isOpen, setIsOpen] = useState(false); return ( <> <button onClick={() => setIsOpen(true)}> Click me </button> {isOpen ? ( <> <div className="backdrop" onClick={() => setIsOpen(false)} ></div> <div className="dialog"> <button className="close-button" onClick={() => setIsOpen(false)} > Close </button> </div> </> ) : null} </> ); }
Kami akan mengawal saiz dialog dengan nama kelas tambahan yang datang daripada prop. Dalam kehidupan sebenar, ia akan sangat bergantung pada penyelesaian penggayaan yang digunakan dalam repo walaupun.
Walau bagaimanapun, dalam varian ini, dialog terlalu fleksibel - hampir semua perkara boleh pergi ke mana-mana. Dalam pengaki, sebagai contoh, kebanyakan masa, kita boleh mengharapkan hanya satu atau dua butang, tidak lebih. Dan butang tersebut perlu disusun secara konsisten di mana-mana di seluruh tapak web. Kita perlu mempunyai pembungkus yang menjajarkannya:
.backdrop { background: rgba(0, 0, 0, 0.3); position: fixed; top: 0; left: 0; width: 100%; height: 100%; }
Sama dengan kandungan - sekurang-kurangnya, ia memerlukan sedikit pelapik di sekelilingnya dan keupayaan menatal. Dan pengepala mungkin memerlukan beberapa gaya untuk teks. Jadi reka letak bertukar menjadi ini:
export default function Page() { const [isOpen, setIsOpen] = useState(false); return ( <> <button onClick={() => setIsOpen(true)}> Click me </button> {isOpen ? ( <div className="dialog">some content</div> ) : null} </> ); }
Tetapi malangnya, kami tidak boleh menjamin itu. Besar kemungkinan, pada satu ketika, seseorang ingin mempunyai sesuatu yang lebih dalam pengaki selain butang. Atau beberapa dialog perlu mempunyai pengepala pada latar belakang yang dijual. Atau kadangkala, kandungan tidak memerlukan pelapik.
Apa yang saya maksudkan di sini ialah kita perlu dapat menggayakan bahagian pengepala/kandungan/pengaki suatu hari nanti. Dan mungkin lebih awal daripada jangkaan.
Kita boleh, sudah tentu, hanya lulus konfigurasi itu dengan prop dan mempunyai sesuatu seperti headerClassName, contentClassName dan footerClassName prop. Dan untuk beberapa kes, ia boleh jadi okay, sebenarnya. Tetapi untuk sesuatu seperti dialog yang bagus untuk reka bentuk semula yang bagus, kami boleh melakukan yang lebih baik.
Cara yang betul-betul kemas untuk menyelesaikan masalah ini ialah dengan mengekstrak pengepala/kandungan/pengaki kita ke dalam komponennya sendiri, seperti ini:
<button className="close-button" onClick={() => setIsOpen(false)} > Close </button>
dan kembalikan kod ModalDialog kepada kod tanpa pembalut:
<div className="backdrop" onClick={() => setIsOpen(false)} ></div>
Dengan cara itu, dalam apl induk, jika saya ingin mempunyai reka bentuk lalai untuk bahagian dialog, saya akan menggunakan komponen kecil tersebut:
export default function Page() { const [isOpen, setIsOpen] = useState(false); return ( <> <button onClick={() => setIsOpen(true)}> Click me </button> {isOpen ? ( <> <div className="backdrop" onClick={() => setIsOpen(false)} ></div> <div className="dialog"> <button className="close-button" onClick={() => setIsOpen(false)} > Close </button> </div> </> ) : null} </> ); }
Dan jika saya mahu mempunyai sesuatu yang tersuai sepenuhnya, saya akan melaksanakan komponen baharu dengan gaya tersuainya sendiri tanpa mengacaukan ModalDialog itu sendiri:
.backdrop { background: rgba(0, 0, 0, 0.3); position: fixed; top: 0; left: 0; width: 100%; height: 100%; }
Untuk itu, saya tidak memerlukan prop header dan footer lagi. Saya hanya boleh menyampaikan DialogHeader dan DialogFooter kepada kanak-kanak, memudahkan lagi ModalDialog dan mempunyai API yang lebih bagus dengan tahap fleksibiliti yang sama sambil mempunyai reka bentuk yang konsisten di mana-mana sahaja.
Komponen induk akan kelihatan seperti ini:
.dialog { position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); }
Dan API dialog akan kelihatan seperti ini:
export default function Page() { const [isOpen, setIsOpen] = useState(false); return ( <> <button onClick={() => setIsOpen(true)}> Click me </button> {isOpen ? ( <> <div className="backdrop" onClick={() => setIsOpen(false)} ></div> <div className="dialog"> <button className="close-button" onClick={() => setIsOpen(false)} > Close </button> </div> </> ) : null} </> ); }
Saya cukup gembira dengannya setakat ini. Ia cukup fleksibel untuk dilanjutkan dalam apa jua cara yang mungkin diperlukan oleh reka bentuk, tetapi ia juga jelas dan cukup masuk akal untuk melaksanakan UI yang konsisten merentas keseluruhan apl dengan mudah.
Berikut ialah contoh langsung untuk dimainkan:
Sekarang API Modal berada dalam bentuk yang cukup baik, tiba masanya untuk menangani senapang kaki jelas yang saya laksanakan. Jika anda sudah cukup membaca artikel saya, anda mungkin telah menjerit dengan kuat, "what r u doing??? Re-render!!" untuk sepuluh minit terakhir? Dan sudah tentu, anda betul:
const ModalDialog = ({ onClose }) => { return ( <> <div className="backdrop" onClick={onClose}></div> <div className="dialog"> <button className="close-button" onClick={onClose}> Close </button> </div> </> ); };
Komponen Halaman di sini mempunyai keadaan. Setiap kali modal dibuka atau ditutup, keadaan akan berubah dan ia akan menyebabkan pemaparan semula keseluruhan komponen dan segala-galanya di dalamnya. Walaupun ya, "pengoptimuman pramatang adalah punca semua kejahatan," dan ya, jangan optimumkan prestasi sebelum benar-benar mengukurnya, dalam kes ini, kita boleh mengabaikan kebijaksanaan konvensional dengan selamat.
Atas dua sebab. Pertama, saya tahu sebenarnya bahawa akan terdapat banyak modal yang tersebar di seluruh apl. Ia bukan ciri tersembunyi sekali sahaja yang tiada siapa akan gunakan. Jadi, kemungkinan seseorang akan meletakkan keadaan di tempat yang tidak sepatutnya dengan API seperti ini agak tinggi. Dan kedua, ia tidak mengambil banyak masa dan usaha untuk menghalang masalah render semula daripada pernah berlaku di tempat pertama. Hanya 1 minit usaha, dan kami tidak perlu memikirkan prestasi di sini sama sekali.
Apa yang perlu kita lakukan ialah merangkum keadaan dan memperkenalkan idea "komponen tidak terkawal":
export default function Page() { const [isOpen, setIsOpen] = useState(false); return ( <> <button onClick={() => setIsOpen(true)}> Click me </button> {isOpen ? ( <div className="dialog">some content</div> ) : null} </> ); }
Di mana BaseModalDialog adalah betul-betul dialog yang sama yang kami ada sebelum ini, saya baru sahaja menamakannya.
Dan kemudian lulus komponen yang sepatutnya mencetuskan dialog sebagai prop pencetus:
<button className="close-button" onClick={() => setIsOpen(false)} > Close </button>
Komponen Halaman kemudian akan kelihatan seperti ini:
<div className="backdrop" onClick={() => setIsOpen(false)} ></div>
Tiada lagi keadaan di dalam Halaman, tiada lagi paparan semula yang berpotensi berbahaya.
API seperti ini harus meliputi 95% daripada kes penggunaan kerana, pada kebanyakan masa, pengguna perlu mengklik pada sesuatu untuk dialog muncul. Dalam situasi yang jarang berlaku apabila dialog perlu dipaparkan secara bebas, contohnya, pada pintasan atau sebagai sebahagian daripada onboarding, saya masih boleh menggunakan BaseModalDialog dan berurusan dengan keadaan secara manual.
API bagi komponen ModalDialog agak kukuh dari perspektif React, tetapi kerja itu hampir selesai. Memandangkan perkara wajib yang saya kumpulkan dalam Langkah 2, saya masih perlu menyelesaikan beberapa isu lagi.
Isu 1: Saya membungkus pencetus ke dalam rentang tambahan - dalam kes tertentu, yang mungkin memecahkan reka letak halaman. Saya perlu membuang pembalut entah bagaimana.
Isu 2: Jika saya memaparkan dialog di dalam elemen yang mencipta Konteks Susunan baharu, modal akan muncul di bawah beberapa elemen. Saya perlu memaparkannya di dalam Portal, bukan terus di dalam reka letak seperti yang saya lakukan sekarang.
Isu 3: Akses papan kekunci agak teruk pada masa ini. Apabila dialog modal yang dilaksanakan dengan betul dibuka, fokus harus melompat ke dalam. Apabila ia ditutup - fokus harus kembali kepada elemen yang mencetuskan dialog. Apabila dialog dibuka, fokus harus "terperangkap" di dalam, dan elemen di luar tidak boleh difokuskan. Menekan butang ESC harus menutup dialog. Tiada satu pun daripada ini dilaksanakan pada masa ini.
Isu 1 dan 2 agak menjengkelkan tetapi boleh diselesaikan dengan agak pantas. Isu 3, bagaimanapun, adalah kesakitan yang besar untuk dilakukan secara manual. Selain itu, pastinya ia adalah masalah yang telah diselesaikan - setiap dialog di mana-mana sahaja memerlukan fungsi ini.
Gabungan "kesakitan yang besar untuk dilakukan sendiri" "nampak seperti pasti masalah selesai" ialah tempat saya akan mencari perpustakaan sedia ada.
Memandangkan semua prakerja yang telah saya lakukan, memilih yang betul adalah mudah sekarang.
Saya boleh pergi ke mana-mana pustaka komponen UI sedia ada seperti Reka Bentuk Semut atau UI Bahan dan menggunakan dialog dari sana. Tetapi jika reka bentuk semula tidak menggunakannya, menyesuaikan reka bentuk mereka kepada yang saya perlukan akan membawa lebih banyak kesakitan daripada yang mereka selesaikan. Jadi, ia adalah NO serta-merta untuk kes ini.
Saya boleh menggunakan salah satu perpustakaan UI "tanpa kepala" seperti Radix atau React Aria. Mereka melaksanakan fungsi seperti keadaan dan pencetus dan semua kebolehaksesan tetapi menyerahkan reka bentuk kepada pengguna. Semasa melihat API mereka, saya perlu menyemak semula bahawa mereka membenarkan saya mengawal keadaan dialog jika saya benar-benar memerlukannya untuk kes di mana saya ingin mencetuskan dialog secara manual (mereka melakukannya).
Jika, atas sebab tertentu, saya tidak boleh menggunakan perpustakaan tanpa kepala, sekurang-kurangnya saya akan cuba menggunakan perpustakaan yang mengendalikan fungsi perangkap fokus.
Demi artikel, anggaplah saya boleh membawa mana-mana perpustakaan yang saya mahu. Dalam kes ini, saya akan menggunakan Radix - ia sangat mudah digunakan dan API dialog kelihatan sangat serupa dengan apa yang telah saya laksanakan, jadi pemfaktoran semula sepatutnya mudah.
Kami perlu menukar sedikit API dialog itu sendiri:
export default function Page() { const [isOpen, setIsOpen] = useState(false); return ( <> <button onClick={() => setIsOpen(true)}> Click me </button> {isOpen ? ( <div className="dialog">some content</div> ) : null} </> ); }
Ia hampir sama seperti saya sebelum ini. Cuma, bukannya div di mana-mana, saya menggunakan primitif Radix.
Penggunaan dialog yang tidak terkawal tidak berubah sama sekali:
<button className="close-button" onClick={() => setIsOpen(false)} > Close </button>
Dan dialog terkawal berubah sedikit - Saya perlu memberikan prop kepadanya dan bukannya rendering bersyarat:
<div className="backdrop" onClick={() => setIsOpen(false)} ></div>
Lihat contoh di bawah dan cuba gunakan papan kekunci untuk menavigasi. Semuanya berfungsi seperti yang saya perlukan, betapa hebatnya?
Sebagai bonus, Radix juga mengendalikan isu Portal, dan ia tidak membungkus pencetus dalam satu tempoh. Saya tidak mempunyai kes tepi untuk diselesaikan lagi, jadi saya boleh meneruskan ke langkah terakhir.
Ciri ini masih belum selesai! ? Dialog kelihatan dan terasa agak kukuh sekarang, jadi saya tidak akan mengubah apa-apa perkara utama dalam pelaksanaannya pada peringkat ini. Tetapi ia masih memerlukan beberapa perkara untuk dianggap dialog "sempurna" untuk kes penggunaan yang saya selesaikan.
Satu: perkara pertama yang pereka bentuk akan minta saya lakukan, jika mereka belum melakukannya, ialah menambah animasi halus apabila dialog dibuka. Perlu menjangkanya dan mengingati cara membuat animasi dalam React.
Dua: Saya perlu menambah lebar maksimum dan ketinggian maksimum pada dialog supaya pada skrin kecil ia masih kelihatan baik. Dan fikirkan bagaimana ia akan kelihatan pada skrin yang sangat besar.
Tiga: Saya perlu berbincang dengan pereka bentuk tentang cara dialog harus berkelakuan pada mudah alih. Kemungkinan besar mereka akan meminta saya menjadikannya panel slaid masuk yang mengambil sebahagian besar skrin tanpa mengira saiz dialog.
Empat: Saya perlu memperkenalkan sekurang-kurangnya komponen DialogTitle dan DialogDescription - Radix akan meminta untuk menggunakannya untuk tujuan kebolehaksesan.
Lima: Ujian! Dialog ini akan kekal dan akan dikekalkan oleh orang lain, jadi ujian adalah sangat wajib dalam kes ini.
Dan mungkin banyak perkara kecil lain yang saya terlupa sekarang yang akan muncul kemudian. Apatah lagi melaksanakan reka bentuk sebenar untuk kandungan dialog.
Jika anda menggantikan "dialog" di atas dengan "SomeNewFeature," ini adalah lebih kurang algoritma yang saya gunakan untuk melaksanakan hampir semua yang baharu.
Pantas "lonjakan" penyelesaian → kumpulkan keperluan untuk ciri → jadikan ia berfungsi → jadikan ia berprestasi → jadikan ia lengkap → jadikannya sempurna.
Untuk sesuatu seperti dialog sebenar, yang telah saya laksanakan beratus kali sekarang, saya akan melakukan langkah pertama dalam 10 saat di kepala saya dan mulakan dengan Langkah 2 serta-merta.
Untuk sesuatu yang sangat rumit dan tidak diketahui, Langkah 1 mungkin lebih panjang dan melibatkan penerokaan penyelesaian dan perpustakaan yang berbeza dengan segera.
Sesuatu yang tidak diketahui, hanya "ciri biasa yang perlu kami lakukan," mungkin melangkau Langkah 1 kerana mungkin tiada apa-apa untuk diterokai.
Agak kerap, terutamanya dalam persekitaran yang "tangkas", ia akan menjadi lebih berbentuk lingkaran daripada garis lurus, di mana keperluan disediakan secara berperingkat dan sering berubah, dan kami kembali ke dua langkah pertama dengan kerap.
Semoga artikel jenis ini berguna! ?? Beritahu saya jika anda ingin mempunyai lebih banyak kandungan seperti ini atau lebih suka perkara biasa "cara perkara berfungsi".
Dan tidak sabar untuk mendengar bagaimana proses ini berbeza dalam fikiran anda semua?
Asal diterbitkan di https://www.developerway.com. Laman web mempunyai lebih banyak artikel seperti ini ?
Lihat buku Advanced React untuk meningkatkan pengetahuan React anda ke peringkat seterusnya.
Langgan surat berita, sambung di LinkedIn atau ikuti di Twitter untuk mendapatkan pemberitahuan sebaik sahaja artikel seterusnya keluar.
Dan btw, satu perkara terakhir: jika anda memulakan projek baharu tidak lama lagi dan tidak mempunyai pereka bentuk dan masa untuk menggilap pengalaman reka bentuk seperti yang diterangkan - baru-baru ini saya menghabiskan berjam-jam (dan berjam-jam) melaksanakan yang baharu perpustakaan komponen UI untuk kes ini. Ia mempunyai komponen copy-pastable dan corak biasa, Radix dan Tailwind, mod gelap, kebolehcapaian dan sokongan mudah alih di luar kotak. Termasuk dialog modal yang sempurna di atas! ?
Cubalah: https://www.buckets-ui.com/
Atas ialah kandungan terperinci Soalan Existential React dan Dialog Modal yang sempurna. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!