Skip to main content
Basic Svelte
Introduction
Reactivity
Props
Logic
Events
Bindings
Classes and styles
Actions
Transitions
Advanced Svelte
Advanced reactivity
Reusing content
Motion
Advanced bindings
Advanced transitions
Context API
Special elements
<script module>
Next steps
Basic SvelteKit
Introduction
Routing
Loading data
Headers and cookies
Shared modules
Forms
API routes
$app/state
Errors and redirects
Advanced SvelteKit
Hooks
Page options
Link options
Advanced routing
Advanced loading
Environment variables
Conclusion

また、データを変更するハンドラを追加することもできます。例えば POST です。ただし、ほとんどのケースでは form actions を使うほうが良いでしょう — 書くコード量が少なくなり、JavaScript なしでも動作するので、よりレジリエンスになります。

‘add a todo’ <input>keydown イベントハンドラの中で、データをサーバーに POST しましょう:

src/routes/+page
<input
	type="text"
	autocomplete="off"
	onkeydown={async (e) => {
		if (e.key !== 'Enter') return;

		const input = e.currentTarget;
		const description = input.value;

		const response = await fetch('/todo', {
			method: 'POST',
			body: JSON.stringify({ description }),
			headers: {
				'Content-Type': 'application/json'
			}
		});

		input.value = '';
	}}
/>

ここでは、ユーザーの cookie にある userid を使用して /todo API ルート(route) に JSON を POST し、新たに作成した todo の id をレスポンスとして受け取っています。

src/routes/todo/+server.js ファイルを追加して、src/lib/server/database.jscreateTodo を呼び出す POST ハンドラを記述し、/todo ルート(route)を作成しましょう。

src/routes/todo/+server
import { json } from '@sveltejs/kit';
import * as database from '$lib/server/database.js';

export async function POST({ request, cookies }) {
	const { description } = await request.json();

	const userid = cookies.get('userid');
	const { id } = await database.createTodo({ userid, description });

	return json({ id }, { status: 201 });
}

load 関数や form actions と同様、request は標準の Request オブジェクトです; await request.json() はイベントハンドラから POST されたデータを返します。

データベースに新たに生成された todo の id をレスポンスとして 201 Created ステータスで返しています。イベントハンドラに戻り、これを使用してページを更新します:

src/routes/+page
<input
	type="text"
	autocomplete="off"
	onkeydown={async (e) => {
		if (e.key !== 'Enter') return;

		const input = e.currentTarget;
		const description = input.value;

		const response = await fetch('/todo', {
			method: 'POST',
			body: JSON.stringify({ description }),
			headers: {
				'Content-Type': 'application/json'
			}
		});

		const { id } = await response.json();

		const todos = [...data.todos, {
			id,
			description
		}];

		data = { ...data, todos };

		input.value = '';
	}}
/>

ページをリロードしても同じ結果が取得できるような方法で data を変更する必要があります。data prop はリアクティブが深くない (not deeply reactive) ので、置き換える必要があります — data.todos = todos のようなミューテーションでは再レンダリングが発生しません。

Edit this page on GitHub

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<script>
	let { data } = $props();
</script>
 
<div class="centered">
	<h1>todos</h1>
 
	<label>
		add a todo:
		<input
			type="text"
			autocomplete="off"
			onkeydown={async (e) => {
				if (e.key !== 'Enter') return;
 
				const input = e.currentTarget;
				const description = input.value;
				
				// TODO handle submit
 
				input.value = '';
			}}
		/>
	</label>
 
	<ul class="todos">
		{#each data.todos as todo (todo.id)}
			<li>
				<label>
					<input
						type="checkbox"
						checked={todo.done}
						onchange={async (e) => {
							const done = e.currentTarget.checked;
 
							// TODO handle change
						}}
					/>
					<span>{todo.description}</span>
					<button
						aria-label="Mark as complete"
						onclick={async (e) => {
							// TODO handle delete
						}}
					></button>
				</label>
			</li>
		{/each}
	</ul>
</div>
 
<style>
	.centered {
		max-width: 20em;
		margin: 0 auto;
	}
 
	label {
		display: flex;
		width: 100%;
	}
 
	input[type="text"] {
		flex: 1;
	}
 
	span {
		flex: 1;
	}
 
	button {
		border: none;
		background: url(./remove.svg) no-repeat 50% 50%;
		background-size: 1rem 1rem;
		cursor: pointer;
		height: 100%;
		aspect-ratio: 1;
		opacity: 0.5;
		transition: opacity 0.2s;
	}
 
	button:hover {
		opacity: 1;
	}
</style>