Pengantar cepat ke Svelte dari perspektif pengembang Angular

Svelte adalah kerangka kerja UI yang relatif baru yang dikembangkan oleh Rich Harris , yang juga penulis pembuat Rollup. Kemungkinan besar, Svelte akan tampak sama sekali berbeda dari apa yang telah Anda tangani sebelumnya, tetapi mungkin ini bahkan baik. Dua fitur yang paling mengesankan dari kerangka kerja ini adalah kecepatan dan kesederhanaan. Pada artikel ini, kita akan fokus pada yang kedua.



Karena pengalaman pengembangan utama saya terkait dengan Angular, wajar jika saya mencoba mempelajari Svelte dengan menyalin pendekatan yang sudah akrab bagi saya. Dan inilah tepatnya yang akan menjadi artikel ini: bagaimana melakukan hal yang sama di Svelte seperti di Angular.


Catatan: Terlepas dari kenyataan bahwa dalam beberapa kasus saya akan menyatakan preferensi saya, artikel ini bukan perbandingan kerangka kerja. Ini adalah pengantar cepat dan mudah untuk Svelte untuk orang-orang yang sudah menggunakan Angular sebagai kerangka kerja utama mereka.


Spoiler peringatan: Svelte menyenangkan.


Komponen


Di Svelte, setiap komponen dikaitkan dengan file di mana ia ditulis. Misalnya, komponen Button akan dibuat dengan memberi nama file Button.svelte . Tentu saja, kami biasanya melakukan hal yang sama di Angular, tetapi bersama kami itu hanya sebuah konvensi. (Di Svelte, nama komponen yang akan diimpor mungkin juga tidak bersamaan dengan nama file - catatan oleh penerjemah)


Komponen langsing adalah file tunggal, dan terdiri dari 3 bagian: script , style dan templat yang tidak perlu dibungkus dengan tag khusus apa pun.


Mari kita membuat komponen yang sangat sederhana yang menunjukkan "Hello World".


hello_world


Komponen Impor


Secara umum, ini mirip dengan mengimpor file JS, tetapi dengan beberapa peringatan:


  • Anda harus secara eksplisit menentukan .svelte file komponen .svelte
  • komponen diimpor di dalam <script>

 <script> import Todo from './Todo.svelte'; </script> <Todo></Todo> 

Dari cuplikan di atas, jelas bahwa jumlah baris untuk membuat komponen di Svelte sangat kecil. Tentu saja, ada beberapa implikasi dan keterbatasan, tetapi pada saat yang sama semuanya cukup sederhana untuk cepat terbiasa dengannya.


Sintaks dasar


Interpolasi


Interpolasi di Svelte lebih mirip dengan yang ada di React daripada di Vue atau Angular:


 <script> let someFunction = () => {...} </script> <span>{ 3 + 5 }</span> <span>{ someFunction() }</span> <span>{ someFunction() ? 0 : 1 }</span> 

Saya dulu menggunakan kawat gigi keriting ganda, jadi saya kadang-kadang disegel, tapi mungkin saya hanya punya masalah ini.


Atribut


Melewati atribut ke komponen juga cukup sederhana. Tanda kutip bersifat opsional dan ekspresi Javascript apa pun dapat digunakan:


 //Svelte <script> let isFormValid = true; </script> <button disabled={!isFormValid}></button> 

Acara


Sintaks untuk event handler adalah: on:={} .


 <script> const onChange = (e) => console.log(e); </script> <input on:input={onChange} /> 

Tidak seperti Angular, kita tidak perlu menggunakan tanda kurung setelah nama fungsi untuk memanggilnya. Jika Anda perlu meneruskan argumen ke handler, cukup gunakan fungsi anonim:


 <input on:input={(e) => onChange(e, 'a')} /> 

Pandangan saya tentang keterbacaan kode tersebut:


  • Kita harus mencetak lebih sedikit, karena kita tidak perlu tanda kutip dan tanda kurung - ini bagus.
  • Baca lebih keras. Saya selalu menyukai pendekatan Angular daripada Bereaksi, jadi bagi saya dan Svelte itu lebih sulit untuk dilakukan. Tapi ini hanya kebiasaan saya dan pendapat saya agak bias.

Arahan struktural


Tidak seperti arahan terstruktur dalam Vue dan Angular, Svelte menawarkan sintaks khusus untuk loop dan cabang di dalam templat:


 {#if todos.length === 0}    {:else} {#each todos as todo} <Todo {todo} /> {/each} {/if} 

Saya sangat menyukainya. Tidak diperlukan elemen HTML tambahan, dan dalam hal keterbacaan, ini terlihat luar biasa. Sayangnya, simbol # pada tata letak keyboard Inggris Macbook saya berada di tempat yang tidak dapat diakses, dan ini secara negatif mempengaruhi pengalaman saya dengan struktur ini.


Properti input


Mendefinisikan properti yang dapat diteruskan ke komponen (analog dengan @Input di Angular) semudah mengekspor variabel dari modul JS menggunakan kata kunci export . Mungkin pada awalnya bisa membingungkan - tapi mari kita tulis contoh dan lihat betapa sederhananya itu:


 <script> export let todo = { name: '', done: false }; </script> <p> { todo.name } { todo.done ? '✓' : '✕' } </p> 

  • Seperti yang Anda lihat, kami menginisialisasi properti todo bersama dengan nilainya: ini akan menjadi nilai properti secara default, jika tidak dilewatkan dari komponen induk

Sekarang buat wadah untuk komponen ini, yang akan mengirimkan data ke dalamnya:


 <script> import Todo from './Todo.svelte'; const todos = [{ name: " Svelte", done: false }, { name: " Vue", done: false }]; </script> {#each todos as todo} <Todo todo={todo}></Todo> {/each} 

Mirip dengan bidang dalam objek JS biasa, todo={todo} dapat dipersingkat dan ditulis ulang sebagai berikut:


 <Todo {todo}></Todo> 

Awalnya terasa aneh bagi saya, tetapi sekarang saya pikir itu brilian.


Properti Keluaran


Untuk menerapkan perilaku arahan @Output , misalnya, ketika komponen induk @Output pemberitahuan dari anak, kami akan menggunakan fungsi createEventDispatcher , yang tersedia di Svelte.


  • Impor fungsi createEventDispatcher dan tetapkan nilai kembalinya ke variabel dispatch
  • Fungsi dispatch memiliki dua parameter: nama acara dan data (yang akan jatuh ke bidang detail objek acara)
  • Kami markDone dispatch di dalam fungsi markDone , yang disebut dengan acara klik ( on:click )

 <script> import { createEventDispatcher } from 'svelte'; export let todo; const dispatch = createEventDispatcher(); function markDone() { dispatch('done', todo.name); } </script> <p> { todo.name } { todo.done ? '✓' : '✕' } <button on:click={markDone}></button> </p> 

Di komponen induk, Anda perlu membuat penangan untuk peristiwa yang done sehingga Anda dapat menandai objek yang diperlukan dalam array todo .


  • Buat fungsi onDone
  • Kami menetapkan fungsi ini ke pengendali event yang dipanggil dalam komponen on:done={onDone} , sebagai berikut: on:done={onDone}

 <script> import Todo from './Todo.svelte'; let todos = [{ name: " Svelte", done: false }, { name: " Vue", done: false }]; function onDone(event) { const name = event.detail; todos = todos.map((todo) => { return todo.name === name ? {...todo, done: true} : todo; }); } </script> {#each todos as todo} <Todo {todo} on:done={onDone}></Todo> {/each} 

Catatan: untuk memicu deteksi perubahan pada suatu objek, kami tidak bermutasi objek itu sendiri. Sebagai gantinya, kami memberikan variabel todos array baru, di mana objek tugas yang diinginkan akan diubah untuk diselesaikan.


Oleh karena itu, Svelte dianggap benar-benar reaktif : dengan penetapan nilai untuk variabel yang biasa, bagian yang sesuai dari representasi juga akan berubah.


ngModel


Svelte memiliki sintaks bind:<>={} khusus bind:<>={} untuk mengikat variabel spesifik ke atribut komponen dan menyinkronkannya satu sama lain.


Dengan kata lain, ini memungkinkan Anda untuk mengatur pengikatan data dua arah:


 <script> let name = ""; let description = ""; function submit(e) { //    } </script> <form on:submit={submit}> <div> <input placeholder="" bind:value={name} /> </div> <div> <input placeholder="" bind:value={description} /> </div> <button> </button> </form> 

Ekspresi Reaktif


Seperti yang kita lihat sebelumnya, Svelte merespons untuk menetapkan nilai ke variabel dan menggambar ulang tampilan. Anda juga dapat menggunakan ekspresi reaktif untuk merespons perubahan nilai satu variabel dan memperbarui nilai lainnya.


Sebagai contoh, mari kita buat variabel yang harus menunjukkan kepada kita bahwa dalam array todos semua tugas ditandai sebagai selesai:


 let allDone = todos.every(({ done }) => done); 

Namun, tampilan tidak akan digambar ulang ketika array diperbarui, karena nilai variabel allDone ditetapkan hanya sekali. Kami akan menggunakan ekspresi reaktif, yang pada saat yang sama akan mengingatkan kita tentang keberadaan "label" di Javascript:


 $: allDone = todos.every(({ done }) => done); 

Terlihat sangat eksotis. Jika Anda merasa "terlalu banyak sihir", saya ingatkan Anda bahwa tag itu Javascript yang valid .


Demo kecil yang menjelaskan hal di atas:
demo


Injeksi konten


Untuk menyematkan konten, slot juga digunakan yang ditempatkan di tempat yang tepat di dalam komponen.


Untuk hanya menampilkan konten yang ditransfer di dalam elemen komponen, elemen slot khusus digunakan:


 // Button.svelte <script> export let type; </script> <button class.type={type}> <slot></slot> </button> // App.svelte <script> import Button from './Button.svelte'; </script> <Button>  </Button> 

Dalam hal ini, baris "" akan menggantikan elemen <slot></slot> .
Slot yang dinamai harus diberi nama:


 // Modal.svelte <div class='modal'> <div class="modal-header"> <slot name="header"></slot> </div> <div class="modal-body"> <slot name="body"></slot> </div> </div> // App.svelte <script> import Modal from './Modal.svelte'; </script> <Modal> <div slot="header">  </div> <div slot="body">  </div> </Modal> 

Kait siklus hidup


Svelte menawarkan 4 kait siklus hidup yang diimpor dari paket svelte .


  • onMount - dipanggil saat komponen dipasang di DOM
  • beforeUpdate - dipanggil sebelum memperbarui komponen
  • afterUpdate - dipanggil setelah pembaruan komponen
  • onDestroy - dipanggil ketika komponen dihapus dari DOM

Fungsi onMount mengambil sebagai parameter fungsi panggilan balik yang akan dipanggil ketika komponen ditempatkan di DOM. Sederhananya, ini mirip dengan ngOnInit kait ngOnInit .


Jika fungsi panggilan balik mengembalikan fungsi lain, itu akan dipanggil ketika komponen dihapus dari DOM.


 <script> import { onMount, beforeUpdate, afterUpdate, onDestroy } from 'svelte'; onMount(() => console.log('', todo)); afterUpdate(() => console.log('', todo)); beforeUpdate(() => console.log('  ', todo)); onDestroy(() => console.log('', todo)); </script> 

Penting untuk diingat bahwa saat memanggil onMount semua properti yang termasuk di dalamnya harus sudah diinisialisasi. Artinya, dalam fragmen di atas, todo seharusnya sudah ada.


Manajemen negara


Mengelola negara Anda di Svelte sangat sederhana, dan mungkin bagian dari kerangka kerja ini lebih bersimpati kepada saya daripada orang lain. Anda bisa melupakan verbositas kode saat menggunakan Redux. Sebagai contoh, kami akan membuat penyimpanan di aplikasi kami untuk penyimpanan dan manajemen tugas.


Vault yang Dapat Direkam


Pertama, Anda perlu mengimpor writable penyimpanan yang writable dari paket initialState svelte/store dan beri tahu nilai awal initialState


 import { writable } from 'svelte/store'; const initialState = [{ name: " Svelte", done: false }, { name: " Vue", done: false }]; const todos = writable(initialState); 

Biasanya, saya meletakkan kode yang sama di file terpisah seperti todos.store.js dan mengekspor variabel penyimpanan dari itu sehingga komponen tempat saya mengimpornya dapat bekerja dengannya.


Jelas, objek todos sekarang telah menjadi repositori dan bukan lagi sebuah array. Untuk mendapatkan nilai penyimpanan, kami akan menggunakan sedikit sihir di Svelte:


  • Dengan menambahkan $ karakter ke nama variabel penyimpanan, kami mendapatkan akses langsung ke nilainya!

Jadi, kita cukup mengganti dalam kode semua referensi ke variabel todos dengan $todos :


 {#each $todos as todo} <Todo todo={todo} on:done={onDone}></Todo> {/each} 

Pengaturan negara


Nilai baru dari penyimpanan yang dapat direkam dapat ditentukan dengan memanggil metode yang set , yang secara imperatif mengubah status menurut nilai yang diteruskan:


 const todos = writable(initialState); function removeAll() { todos.set([]); } 

Pembaruan status


Untuk memperbarui penyimpanan (dalam kasus kami, todos ), berdasarkan kondisi saat ini, Anda perlu memanggil metode update dan memberikannya fungsi panggilan balik yang akan mengembalikan status baru untuk penyimpanan.


Kami menulis ulang fungsi onDone yang kami buat sebelumnya:


 function onDone(event) { const name = event.detail; todos.update((state) => { return state.map((todo) => { return todo.name === name ? {...todo, done: true} : todo; }); }); } 

Di sini saya menggunakan peredam langsung pada komponen, yang merupakan praktik buruk. Kami memindahkannya ke file dengan repositori kami dan mengekspor fungsi darinya yang hanya akan memperbarui keadaan.


 // todos.store.js export function markTodoAsDone(name) { const updateFn = (state) => { return state.map((todo) => { return todo.name === name ? {...todo, done: true} : todo; }); }); todos.update(updateFn); } // App.svelte import { markTodoAsDone } from './todos.store'; function onDone(event) { const name = event.detail; markTodoAsDone(name); } 

Ubah Status Berlangganan


Untuk mengetahui bahwa nilai dalam repositori telah berubah, Anda dapat menggunakan metode subscribe . Ingatlah bahwa repositori bukan objek yang observable , tetapi menyediakan antarmuka yang serupa.


 const subscription = todos.subscribe(console.log); subscription(); //     

Dapat diobservasi


Jika bagian ini menyebabkan Anda kegembiraan terbesar, maka saya cepat-cepat menyenangkan bahwa belum lama ini, dukungan RxJS ditambahkan ke Svelte dan Observable for ECMAScript diperkenalkan.


Sebagai pengembang Angular, saya sudah terbiasa bekerja dengan pemrograman reaktif, dan kurangnya mitra pipa async akan sangat merepotkan. Tapi Svelte juga mengejutkanku di sini.


Mari kita lihat contoh bagaimana alat-alat ini bekerja bersama: tampilkan daftar repositori di Github, ditemukan oleh kata kunci "Svelte" .


Anda dapat menyalin kode di bawah ini dan menjalankannya langsung di REPL :


 <script> import rx from "https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"; const { pluck, startWith } = rx.operators; const ajax = rx.ajax.ajax; const URL = `https://api.github.com/search/repositories?q=Svelte`; const repos$ = ajax(URL).pipe( pluck("response"), pluck("items"), startWith([]) ); </script> {#each $repos$ as repo} <div> <a href="{repo.url}">{repo.name}</a> </div> {/each} <!--   Angular: <div *ngFor="let repo of (repos$ | async)> <a [attr.href]="{{ repo.url }}">{{ repo.name }}</a> </div> --> 

Cukup tambahkan simbol $ ke nama repos$ variabel yang dapat diamati repos$ dan Svelte akan secara otomatis menampilkan isinya.


Daftar harapan saya untuk Svelte


Dukungan naskah


Sebagai penggila naskah, saya tidak bisa tidak berharap untuk kemungkinan menggunakan jenis di Svelte. Saya sangat terbiasa sehingga kadang-kadang saya terbawa dan mengatur jenis dalam kode saya, yang kemudian harus saya hapus. Saya sangat berharap bahwa Svelte akan segera menambahkan dukungan untuk naskah. Saya pikir item ini akan menjadi daftar keinginan siapa pun yang ingin menggunakan Svelte dengan pengalaman dengan Angular.


Perjanjian dan pedoman


Rendering dalam representasi variabel apa pun dari blok <script> adalah fitur yang sangat kuat dari kerangka kerja, tetapi menurut pendapat saya, itu dapat menyebabkan kekacauan kode. Saya berharap bahwa komunitas Svelte akan bekerja melalui sejumlah konvensi dan pedoman untuk membantu pengembang menulis kode komponen yang bersih dan dapat dipahami.


Dukungan masyarakat


Svelte adalah proyek muluk, yang, dengan upaya peningkatan masyarakat dalam menulis paket pihak ketiga, manual, artikel blog dan banyak lagi, dapat lepas landas dan menjadi alat yang diakui dalam dunia pengembangan Frontend yang menakjubkan yang kita miliki saat ini.


Kesimpulannya


Terlepas dari kenyataan bahwa saya bukan penggemar kerangka versi sebelumnya, Svelte 3 membuat kesan yang baik pada saya. Ini sederhana, kecil, tetapi bisa melakukan banyak hal. Ini sangat berbeda dari semua yang ada di sekitar yang mengingatkan saya pada kegembiraan yang saya alami ketika saya beralih dari jQuery ke Angular.


Apa pun kerangka yang Anda gunakan sekarang, mempelajari Svelte kemungkinan hanya akan memakan waktu beberapa jam. Setelah Anda mempelajari dasar-dasarnya dan memahami perbedaan dengan apa yang Anda gunakan untuk menulis, bekerja dengan Svelte akan sangat mudah.


Di saluran Telegram berbahasa Rusia @sveltejs Anda pasti akan menemukan pengembang yang memiliki pengalaman dengan berbagai kerangka kerja dan siap untuk berbagi kisah, pemikiran, dan kiat mereka tentang Svelte.

Source: https://habr.com/ru/post/id467091/


All Articles