Jadi Svelte v5, persembahan terbaharu yang mungkin merupakan rangka kerja hadapan terbaik yang wujud, telah dikeluarkan dan ia jauh berbeza daripada versi sebelumnya. Perbezaan utama terletak pada terasnya: Bagaimana kereaktifan pembolehubah dilaksanakan. Disebabkan perubahan ini, Svelte menjadi lebih mudah, dan pada masa yang sama menjadi lebih sukar.
Memandangkan saya telah bekerja keras dengan Svelte v5 sejak v5@next.155 dalam projek bahagian hadapan mikro dunia sebenar, saya memutuskan untuk menulis siri artikel ini untuk menyampaikan pengetahuan saya yang diperoleh untuk membantu anda memahami, menerima dan berpotensi memindahkan kod anda ke Svelte v5.
Sistem kereaktifan Svelte v4 adalah karya seni: Svelte menganalisis kod dalam komponen secara statik dan kemudian menjana kod yang secara mustahak mengubah DOM apabila pembolehubah JavaScript biasa berubah. Mudah, elegan, dan sangat berprestasi. Contoh cepat:
<script lang="ts"> let clickCount = 0; function countClicks() { ++clickCount; } </script> <svelte:document on:click={() => countClicks()} /> <pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}
Komponen mudah ini menambahkan pendengar acara "klik" pada objek dokumen dan mengira klik. Kiraan klik dipaparkan dalam masa nyata dengan hanya kod di atas. Hebat kan?
Seperti segala-galanya dalam hidup, ini tidak sempurna. Rich Harris (pencipta Svelte) telah menjelaskan kaveat, dan saya tidak akan membacanya dalam artikel ini. Saya hanya akan menyebut satu: Kod refactor.
Salah satu kaveat yang lebih penting ialah ketidakupayaan untuk membawa sistem kereaktifan ini di luar komponen. Sebagai contoh, seseorang tidak boleh mencipta modul boleh guna semula yang merangkumi pelaksanaan fungsi countClicks dalam contoh.
Oleh kerana kereaktifan bergantung pada analisis statik, mengambil fungsi dan masuk ke dalam modul akan menyembunyikan mutasi pembolehubah kepada penganalisis kod statik dan kemudian kereaktifan hilang.
Istilah rune merujuk kepada "simbol ajaib", dan merupakan istilah yang diterima pakai oleh Svelte untuk menamakan terlihat fungsi istilah "sihir" berikut:
$negeri
$props
$boleh diikat
$derived
$kesan
Kereaktifan dalam Svelte v5 dikawal oleh penggunaan rune ini.
Adalah penting untuk ambil perhatian bahawa walaupun ia kelihatan seperti nilai-R, kod yang dihasilkan adalah benar-benar nilai-L. Dalam erti kata lain, jangan fikir anda boleh meneruskan keadaan dari pembolehubah ke pembolehubah. Ini diperincikan sedikit lagi di bawah dalam bahagian $state rune.
Kelebihan utama sistem kereaktifan baharu ini ialah:
Keupayaan untuk memfaktorkan semula kod reaktif di luar komponen
Kereaktifan berbutir halus
Yang pertama bermakna kita boleh mempunyai pembolehubah reaktif di luar komponen; yang terakhir ini bermakna pemaparan semula komponen lebih disasarkan apabila ia bertindak balas terhadap keadaan yang berubah.
Keupayaan untuk mempunyai komponen luar negeri tidak diliputi dalam artikel ini tetapi ikuti siri ini kerana artikel tentang perkara ini akan datang.
Kereaktifan berbutir halus, sebaliknya, bermakna Svelte kini boleh mengetahui sifat mana yang berubah dalam objek keadaan dan hanya memaparkan semula (dan menjalankan semula kesan dan mengira semula nilai terbitan) perkara yang dipengaruhi oleh sifat khusus tersebut sahaja. Ini dalam beberapa kes peningkatan prestasi yang besar. Sebagai contoh pantas: Jika komponen jadual besar melihat baris baharu ditambahkan pada datanya, Svelte hanya akan memaparkan baris baharu. Jika nilai sel tunggal dalam baris ke-3 berubah, hanya sel yang menunjukkan nilai akan dipaparkan semula. Adakah ia jelas sekarang? Mudah-mudahan begitu, tetapi jika tidak, tekan saya di bahagian Komen.
Rune ini digunakan untuk mencipta keadaan reaktif. Mari tulis semula sampel kod Svelte v4 dari atas:
<script lang="ts"> let clickCount = 0; function countClicks() { ++clickCount; } </script> <svelte:document on:click={() => countClicks()} /> <pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}
Untuk mencapai hasil yang sama seperti yang kami lakukan dalam Svelte v4, kami hanya menggunakan $state(0) dan bukannya 0.
Peraturan utama yang mengawal rune ini ialah ia hanya boleh digunakan untuk memulakan pembolehubah atau medan kelas dan ia mempunyai kaitan dengan nota penting yang anda baca seminit yang lalu: Rune kelihatan seperti fungsi secara sintaksis, tetapi tidak. Pengkompil menggantikan rune dengan kod yang tidak serasi dengan idea tentang fungsi fungsi, iaitu mengira dan mengembalikan nilai. Ini bermakna yang berikut tidak mewujudkan pembolehubah reaktif kedua:
<script lang="ts"> let clickCount = $state(0); function countClicks() { ++clickCount; } </script> <svelte:document onclick={() => countClicks()} /> <pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}
Sifat reaktif clickCount tidak dipindahkan atau disalin ke secondClickCount berdasarkan penggunaan operator tugasan. Jika rune ialah fungsi, perkara di atas akan berfungsi, tetapi tidak.
Ada satu lagi perkara penting untuk disebut tentang $state: Ia menjadikan nilainya sangat reaktif. Ini bermakna jika nilai adalah objek yang sifatnya mengandungi objek, maka sifat objek yang terkandung juga reaktif. Corak ini digunakan secara rekursif, jadi keseluruhan graf objek akhirnya reaktif.
Sifat komponen dijangka reaktif, dan Svelte v5 mencapai ini menggunakan rune $props.
<script lang="ts"> let clickCount = $state(0); let secondClickCount = clickCount; function countClicks() { ++clickCount; } </script>
Oleh kerana menggunakan TypeScript adalah segala-galanya untuk projek, kami mulakan dengan mengisytiharkan sifat komponen menggunakan jenis. Sifat pilihan ditandakan dengan melampirkan ? kepada namanya.
Kemudian datang penggunaan rune, yang merupakan pernyataan penstrukturan. Contoh menunjukkan cara menetapkan nilai lalai dan cara membenarkan sifat "rehat", iaitu sebarang harta lain. Komponen menyebarkan (menggunakan) "selebihnya" sifat ini sebagai sifat (atribut) pada elemen HTML span.
Anda boleh lakukan let props: Props = $props(); untuk menentukan sifat dan ia berfungsi, tetapi kemudian anda tidak boleh menentukan lalai untuk pelbagai sifat, jadi saya cadangkan anda sentiasa mengisytiharkan sifat seperti yang ditunjukkan. Saya juga tidak akan tahu cara mengisytiharkan restProperties sama ada jika tidak menyahstruktur, bukan-bukan.
Jika anda telah memberi perhatian, perkara di atas menghasilkan ralat TypeScript. Lagipun, jenis Props tidak menyebut tentang sebarang harta "rehat". Bagaimanakah kita boleh menaip restProps?
Secara umumnya, anda boleh melakukan perkara seperti berikut untuk membenarkan semua jenis bahan. Terpulang kepada kemahiran TypeScript anda, saya rasa.
Yang berikut membuka taip Props untuk membenarkan sebarang atribut data-*:
<script lang="ts"> let clickCount = 0; function countClicks() { ++clickCount; } </script> <svelte:document on:click={() => countClicks()} /> <pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}
Yang ini membenarkan apa sahaja:
<script lang="ts"> let clickCount = $state(0); function countClicks() { ++clickCount; } </script> <svelte:document onclick={() => countClicks()} /> <pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}
Tetapi lebih kerap daripada tidak, seseorang perlu membenarkan atribut elemen HTML yang menerima restProps, dan dalam contoh kami, itu ialah elemen HTML span.
Untuk senario biasa ini, Svelte v5 menyediakan jenis yang harus merangkumi kebanyakan elemen HTML:
<script lang="ts"> let clickCount = $state(0); let secondClickCount = clickCount; function countClicks() { ++clickCount; } </script>
Menggunakan yang kedua akan menjadikan GUI seperti VS Code memberikan Intellisense yang tepat pada prop (atribut) yang mungkin untuk elemen HTML rentang. Bagus, kan?
Atribut HTML
antara muka digunakan untuk elemen HTML yang tidak mempunyai kekhususan dalam senarai sifatnya. Banyak elemen, bagaimanapun, mempunyai. Contohnya, daripada melakukan HTMLAttributes , import antara muka HTMLButtonAttributes daripada 'svelte/elements'.
Butiran terakhir ialah nilai lalai. Tidak banyak yang perlu diperkatakan dan contoh menyatakan semuanya: Nilai lalai prop operasi ialah 'jumlah'. Jika sifat tidak dinyatakan apabila komponen digunakan, itulah nilai prop yang akan diandaikan.
Jika lalai yang dikehendaki tidak ditentukan, maka jangan nyatakan apa-apa pun.
Ini adalah rune yang sangat spesifik yang hanya boleh digunakan dalam sifat komponen. Ia menandakan harta sebagai boleh diikat.
Jika anda tidak tahu atau tidak ingat, Svelte membenarkan pengikatan sifat 2 hala. Vue juga mempunyai ciri ini, dan sebaliknya, React tidak.
Penggunaan sangat mudah:
<script lang="ts"> type Props = { data: number[]; operation?: 'sum', 'avg'; }; let { data, operation = 'sum', ...restProps, }: Props = $props(); function sum() { return data.reduce((p, c) => p + c); } function avg() { return sum() / data.length } </script> <span class="amount" {...restProps}>{operation === 'sum' ? sum() : avg()}</span> <style> .amount { font-family: monospace; } </style>
Sentiasa jadikan sifat yang diubah suai nilainya sebagai boleh diikat atau Svelte akan mengadu dengan amaran konsol. Amaran menyatakan bahawa komponen tidak boleh mengubah suai keadaan yang bukan miliknya dan jika ini dimaksudkan, maka pengikatan harus digunakan.
Seperti yang ditunjukkan dalam contoh, seseorang boleh menentukan lalai sifat melalui rune $bindable. Contoh menetapkan lalai harta itu kepada 5.
Tetapi adakah lalai juga masuk akal di sini? Nah, ya. Mengisytiharkan harta sebagai boleh diikat tidak memerlukannya.
Apabila kita perlu mengira nilai menggunakan nilai daripada prop atau keadaan reaktif lain (yang boleh berubah dari semasa ke semasa), kita menggunakan rune $derived.
Membawa semula komponen contoh yang mengira jumlah dan purata, kita boleh menulis semula menggunakan rune ini:
<script lang="ts"> let clickCount = 0; function countClicks() { ++clickCount; } </script> <svelte:document on:click={() => countClicks()} /> <pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}
Kini kami mempunyai pembolehubah baharu bernama hasil yang reaktif seperti inputnya dan akan mengira semula secara automatik setiap kali data dalam tatasusunan data berubah. Ia sendiri ialah pembolehubah reaktif, jadi templat (bahagian HTML komponen) yang menggunakannya juga akan dikemas kini.
Rune ini membolehkan kami menentukan kod arbitrari yang dijalankan apabila data reaktif berubah. Untuk menjalankan keajaiban rune ini, ia menjejaki data reaktif yang dibaca semasa pelaksanaannya. Inventori data reaktif ini kemudiannya digunakan untuk mencetuskan semula kesan apabila apa-apa dalam inventori mengubah nilainya.
Mungkin senario yang paling biasa ialah mencetuskan semula operasi pengambilan data berdasarkan perubahan nilai:
<script lang="ts"> let clickCount = $state(0); function countClicks() { ++clickCount; } </script> <svelte:document onclick={() => countClicks()} /> <pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}
Operasi tak segerak biasanya merupakan kesan dalaman yang biasa apabila kita tidak mahu pembolehubah $derived kami memegang janji. Secara peribadi, walaupun dan kerana ia sangat mudah untuk bekerja dengan janji dalam Svelte, saya hanya akan menggunakan nilai $derived. Varian yang ditunjukkan seterusnya menjadikan data sebagai nilai terkira reaktif yang memegang janji:
<script lang="ts"> let clickCount = $state(0); let secondClickCount = clickCount; function countClicks() { ++clickCount; } </script>
Secara umumnya, jika anda melakukan gabungan $state dan $effect, kemungkinan besar anda lebih baik menggunakan $derived. Walau bagaimanapun, terdapat pengecualian untuk peraturan ini, jadi anggap ia sebagai peraturan biasa dan bukan Firman Suci.
Jika pengambilan data bukan contoh yang baik untuk $effect, maka apakah itu? Mari lihat yang ini:
<script lang="ts"> type Props = { data: number[]; operation?: 'sum', 'avg'; }; let { data, operation = 'sum', ...restProps, }: Props = $props(); function sum() { return data.reduce((p, c) => p + c); } function avg() { return sum() / data.length } </script> <span class="amount" {...restProps}>{operation === 'sum' ? sum() : avg()}</span> <style> .amount { font-family: monospace; } </style>
Ini ialah komponen pemasa mudah yang dikawal melalui sifat statusnya. Rune $effect digunakan di sini untuk menguatkuasakan operasi pemasa. Bolehkah anda bayangkan memfaktorkan semula ini kepada $derived? Ngomong-ngomong, jangan cuba kerana telah berlalu ialah prop, jadi ia tidak boleh $derived dan prop pada masa yang sama.
Svelte v5 didatangkan dengan enjin kereaktifan serba baharu yang menjurus ke arah prestasi yang lebih baik dalam pemaparan semula dan pemfaktoran semula kod yang lebih baik. Menggunakan sistem kereaktifan baharu adalah mudah dan kompleks: Mudah kerana senario biasa diliputi dengan baik oleh reka bentuk sistem dan sedikit lebih sukar kerana, jika dibandingkan dengan v4, kod itu menjadi sedikit lebih kompleks.
Walau apa pun, sistem baharu ini berkuasa dan memenuhi kebanyakan senario dengan anggun dan berkesan, menyediakan rune untuk semua kemungkinan yang mudah digunakan, walaupun agak ganjil pada mulanya.
Artikel ini hanya merangkumi bahagian pengenalan rune, ditambah dengan sedikit pengalaman peribadi menggunakannya. Terdapat lebih banyak topik yang perlu dibincangkan untuk membantu anda, rakan pembaca, meningkatkan dengan lebih pantas dengan persembahan baharu Svelte ini, iaitu:
Pengetahuan mendalam tentang cara $effect berfungsi
Lari lanjutan ($state.raw, $derived.by, $effect.pre, dll.)
Menggantikan kedai dengan keadaan reaktif
Senario di luar kebiasaan
Lihat hasil penanda aras ini: Keputusan Interaktif (krausest.github.io)
Kini, senarai rangka kerja adalah mengerikan, jadi anda boleh menyalin JSON berikut, dan kemudian menampalnya ke halaman web menggunakan butang Tampal (lihat tangkapan skrin):
<script lang="ts"> let clickCount = 0; function countClicks() { ++clickCount; } </script> <svelte:document on:click={() => countClicks()} /> <pre class="brush:php;toolbar:false">Clicks inside document: {clickCount}
Sebenarnya, saya rasa memfokuskan tetingkap dan menampal melalui papan kekunci juga berfungsi.
Ini mengecilkan senarai rangka kerja kepada yang lebih popular, atau sekurang-kurangnya perkara yang saya anggap popular. Mungkin anda lebih tahu daripada saya.
Memang memalukan bahawa Svelte v4 tidak lagi tersedia dalam carta, tetapi seperti yang anda lihat, daripada rangka kerja yang dipilih, 3 teratas tidak boleh dipertikaikan: Vanilla JS, Solid dan Svelte.
Di hujung spektrum yang lain, sungguh menyedihkan melihat React v19 berprestasi begitu teruk. Bukankah pengkompil sepatutnya menjadikannya lebih baik? Nampaknya ia akhirnya menjadi sia-sia usaha. Sudah tentu, ia nampaknya mengungguli React v18, tetapi itu sahaja. Saya tidak pasti mengapa Meta terus melabur wang dalam React. Fikir, sesiapa?
Atas ialah kandungan terperinci Mempelajari Sistem veaktiviti Svelte baharu. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!