SvelteKit sangat cocok untuk latihan dasar full-stack karena satu project dapat menangani UI, routing, form, dan endpoint server dalam struktur yang rapi. Untuk belajar konsep CRUD tanpa menambah kompleksitas database, kita bisa memakai in-memory array sebagai penyimpanan sementara. Pendekatan ini tidak cocok untuk produksi, tetapi sangat baik untuk memahami alur data dari form ke server lalu kembali ke halaman.
Dalam artikel ini kita akan membuat mini project todo sederhana dengan fitur berikut:
- Menampilkan daftar todo
- Menambah item todo
- Memperbarui item todo
- Menghapus item todo
Kita akan menggunakan SvelteKit + form actions agar implementasi tetap sederhana. Semua data disimpan di memori server, jadi saat server restart, data akan hilang. Justru itu membuat contoh ini ringan dan mudah dipahami.
Persiapan Project
Jika Anda belum memiliki project SvelteKit, buat project baru terlebih dahulu. Perintah dasarnya seperti berikut:
npm create svelte@latest todo-sveltekit
cd todo-sveltekit
npm install
npm run devSaat inisialisasi, pilih template dasar sesuai kebutuhan. Untuk tutorial ini, kita tidak membutuhkan database atau library tambahan.
Struktur file yang akan kita gunakan:
src/
lib/
server/
todos.js
routes/
+page.server.js
+page.svelteFokus kita hanya pada satu halaman utama agar CRUD mudah diikuti.
Membuat Penyimpanan In-Memory
Buat file src/lib/server/todos.js. File ini akan menyimpan array todo dan helper function sederhana untuk operasi CRUD.
let todos = [
{ id: 1, text: 'Belajar SvelteKit', done: false },
{ id: 2, text: 'Membuat CRUD todo', done: true }
];
let nextId = 3;
export function getTodos() {
return todos;
}
export function addTodo(text) {
const todo = {
id: nextId++,
text,
done: false
};
todos = [todo, ...todos];
return todo;
}
export function deleteTodo(id) {
todos = todos.filter((todo) => todo.id !== id);
}
export function updateTodo(id, text, done) {
todos = todos.map((todo) =>
todo.id === id
? { ...todo, text, done }
: todo
);
}
Mengapa dipisah ke file sendiri? Karena logika data menjadi lebih rapi dan tidak bercampur langsung dengan file route. Walaupun sederhana, struktur seperti ini lebih mudah dikembangkan nanti jika Anda ingin mengganti penyimpanan ke database sungguhan.
Catatan penting: data in-memory hanya bertahan selama proses server hidup. Jika server restart, hot reload tertentu terjadi, atau aplikasi berjalan pada banyak instance, data bisa hilang atau tidak konsisten.
Membuat Load Function dan Form Actions
Selanjutnya, buat file src/routes/+page.server.js. File ini akan melakukan dua hal:
- Mengirim data todo ke halaman melalui
load - Menangani aksi form untuk tambah, hapus, dan update
import { fail } from '@sveltejs/kit';
import { getTodos, addTodo, deleteTodo, updateTodo } from '$lib/server/todos';
export function load() {
return {
todos: getTodos()
};
}
export const actions = {
add: async ({ request }) => {
const formData = await request.formData();
const text = formData.get('text')?.toString().trim();
if (!text) {
return fail(400, {
error: 'Teks todo wajib diisi.'
});
}
addTodo(text);
return { success: true };
},
delete: async ({ request }) => {
const formData = await request.formData();
const id = Number(formData.get('id'));
if (!id) {
return fail(400, {
error: 'ID todo tidak valid.'
});
}
deleteTodo(id);
return { success: true };
},
update: async ({ request }) => {
const formData = await request.formData();
const id = Number(formData.get('id'));
const text = formData.get('text')?.toString().trim();
const done = formData.get('done') === 'on';
if (!id || !text) {
return fail(400, {
error: 'Data update tidak valid.'
});
}
updateTodo(id, text, done);
return { success: true };
}
};Beberapa hal penting dari implementasi di atas:
load()dipanggil untuk mengambil data todo dan mengirimkannya ke halaman.actionsmemudahkan kita menangani form POST tanpa harus membuat endpoint API terpisah.fail(400, ...)digunakan untuk mengirim error validasi yang bisa ditampilkan kembali di UI.- Input tetap divalidasi di server meskipun form berasal dari halaman kita sendiri.
Pendekatan ini cocok jika interaksi Anda sederhana dan berbasis form. Untuk aplikasi yang lebih kompleks, Anda bisa mempertimbangkan endpoint +server.js dan fetch dari client.
Membuat Halaman Todo
Sekarang buat file src/routes/+page.svelte. Di sinilah kita menampilkan daftar todo dan form untuk menambah, mengubah, serta menghapus data.
<script>
export let data;
export let form;
</script>
<svelte:head>
<title>Todo Sederhana</title>
</svelte:head>
<h2>Todo List</h2>
{#if form?.error}
<p style="color: red;">{form.error}</p>
{/if}
<form method="POST" action="?/add" style="margin-bottom: 1rem;">
<input
type="text"
name="text"
placeholder="Tulis todo baru"
required
/>
<button type="submit">Tambah</button>
</form>
{#if data.todos.length === 0}
<p>Belum ada todo.</p>
{:else}
<ul style="list-style: none; padding: 0;">
{#each data.todos as todo}
<li style="border: 1px solid #ddd; padding: 1rem; margin-bottom: 1rem;">
<form method="POST" action="?/update">
<input type="hidden" name="id" value={todo.id} />
<input
type="text"
name="text"
value={todo.text}
required
/>
<label style="margin-left: 0.5rem;">
<input
type="checkbox"
name="done"
checked={todo.done}
/>
Selesai
</label>
<button type="submit" style="margin-left: 0.5rem;">
Update
</button>
</form>
<form method="POST" action="?/delete" style="margin-top: 0.5rem;">
<input type="hidden" name="id" value={todo.id} />
<button type="submit">Hapus</button>
</form>
</li>
{/each}
</ul>
{/if}Kode ini sengaja dibuat sederhana. Setiap item todo memiliki dua form:
- Form update untuk mengubah teks dan status selesai
- Form delete untuk menghapus item
Selain itu, ada satu form di atas daftar untuk menambahkan todo baru.
Mengapa Menggunakan Banyak Form?
Dalam SvelteKit, form actions sangat nyaman untuk skenario seperti ini. Setiap form bisa langsung diarahkan ke action tertentu dengan action="?/add", action="?/update", dan action="?/delete". Hasilnya:
- Tidak perlu menulis JavaScript client tambahan hanya untuk CRUD dasar
- Proses lebih mudah di-debug karena mengikuti alur HTTP form biasa
- Validasi server tetap menjadi pusat logika
Trade-off-nya, interaksi tidak se-dinamis aplikasi SPA murni kecuali Anda menambahkan enhancement seperti use:enhance. Namun untuk latihan dasar, pendekatan ini justru lebih jelas.
Alur CRUD yang Terjadi
1. Read: Menampilkan Data
Saat halaman dibuka, load() pada +page.server.js memanggil getTodos(). Nilai itu dikirim ke komponen sebagai data.todos, lalu ditampilkan dengan blok {#each}.
2. Create: Menambah Todo
Form tambah mengirim request POST ke action add. Di sana server membaca field text, memvalidasi bahwa nilainya tidak kosong, lalu memanggil addTodo(text). Setelah action selesai, halaman dirender ulang dengan data terbaru.
3. Update: Mengubah Todo
Form update mengirim id, text, dan checkbox done. Server lalu memanggil updateTodo(id, text, done). Teknik ini sederhana dan cukup untuk edit inline dasar.
4. Delete: Menghapus Todo
Form delete hanya mengirim id. Action delete akan memfilter array berdasarkan id tersebut.
Keterbatasan Pendekatan Tanpa Database
Sebelum melanjutkan, penting untuk memahami keterbatasannya:
- Data hilang saat server restart. Karena hanya disimpan di memori, tidak ada persistensi.
- Tidak cocok untuk multi-user sungguhan. Semua pengguna melihat dan memodifikasi array yang sama.
- Tidak aman untuk data penting. Tidak ada autentikasi, otorisasi, atau penyimpanan permanen.
- Bisa bermasalah di deployment tertentu. Pada environment serverless atau instance ganda, state in-memory bisa berbeda-beda.
Meski begitu, untuk latihan konsep CRUD, routing, server action, dan validasi dasar, pendekatan ini sangat efektif.
Kesalahan Umum dan Tips Debugging
1. Form action tidak terpanggil
Pastikan atribut method="POST" dan action="?/namaAction" ditulis dengan benar. Jika nama action salah, request tidak akan masuk ke handler yang diharapkan.
2. Nilai checkbox membingungkan
Pada form HTML, checkbox yang dicentang akan mengirim nilai, sedangkan yang tidak dicentang tidak mengirim apa pun. Karena itu kita gunakan:
const done = formData.get('done') === 'on';Jika Anda lupa pola ini, status boolean bisa terbaca salah.
3. ID menjadi string
Semua nilai dari FormData dibaca sebagai string. Karena itu ID perlu dikonversi:
const id = Number(formData.get('id'));Jika tidak dikonversi, perbandingan dengan angka di array bisa gagal.
4. Data tidak terlihat berubah
Pastikan fungsi helper benar-benar memperbarui array. Misalnya, map dan filter harus disimpan kembali ke variabel todos. Jika hanya dipanggil tanpa assignment, datanya tidak berubah.
5. Validasi hanya di client
Jangan mengandalkan atribut required saja. Pengguna tetap bisa mengirim request yang tidak valid. Validasi harus tetap dilakukan di server.
Alternatif: Memakai Endpoint +server.js
Jika Anda ingin memisahkan UI dari API, Anda bisa membuat endpoint seperti src/routes/api/todos/+server.js lalu memanggilnya lewat fetch. Pendekatan ini lebih fleksibel untuk integrasi front-end dinamis, tetapi untuk tutorial dasar justru menambah file dan kompleksitas.
Kapan sebaiknya memakai form actions?
- Saat interaksi berbasis form sederhana
- Saat ingin mengurangi JavaScript client
- Saat ingin validasi dan submit tetap natural seperti HTML biasa
Kapan endpoint API lebih cocok?
- Saat Anda butuh UI yang sangat interaktif
- Saat front-end melakukan banyak operasi async tanpa reload
- Saat API akan dipakai oleh route atau aplikasi lain
Penutup
Dengan mini project ini, Anda sudah mempraktikkan dasar CRUD di SvelteKit tanpa database: membaca data melalui load, menambah item lewat form action, memperbarui item dengan form inline, dan menghapus item berdasarkan ID. Walaupun penyimpanan masih memakai array in-memory, pola kode ini cukup dekat dengan implementasi nyata sehingga mudah ditingkatkan ke database seperti SQLite, PostgreSQL, atau layanan backend lain.
Jika ingin melanjutkan latihan, beberapa pengembangan yang masuk akal adalah:
- Menambahkan filter todo selesai/belum selesai
- Menambahkan validasi panjang teks
- Menambahkan notifikasi sukses atau gagal
- Menggunakan
use:enhanceagar submit lebih halus tanpa reload penuh - Mengganti array in-memory dengan database sungguhan
Untuk tahap awal, fokus utama adalah memahami alur request, form, action, dan render ulang data. Setelah konsep ini kuat, Anda akan jauh lebih mudah membangun aplikasi SvelteKit yang lebih kompleks.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!