Svelte入門:SvelteKitでのフォームアクション -Vol.3-

スポンサーリンク
Svelte入門:SvelteKitでのフォームアクション -Vol.3- 用語解説
Svelte入門:SvelteKitでのフォームアクション -Vol.3-
この記事は約8分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

今日は、SvelteKitでのフォームアクションについて解説しています。

スポンサーリンク

背景

SvelteKitでのフォームアクションについて調査する機会がありましたので、その時の内容を備忘として記事に残しました。

SvelteKitでのフォームアクションについて

+page.server.jsファイルでは「アクション」をエクスポートできます。これにより、<form>要素を使用してサーバーにデータをPOSTすることが可能になります。<form>を使用する際、クライアントサイドのJavaScriptは任意ですが、JavaScriptを使って簡単にフォームの操作を段階的に強化し、最高のユーザー体験を提供することができます。

アクションの構造

各アクションはRequestEventオブジェクトを受け取り、これによりrequest.formData()を使用してデータを読み取ることができます。リクエストの処理(例えば、クッキーを設定してユーザーをログインさせるなど)の後、アクションはデータを返すことができます。このデータは、次の更新まで、対応するページのformプロパティを通じて、そしてアプリ全体で$page.formを通じて利用可能になります。

// src/routes/login/+page.server.js
/** @type {import('./$types').PageServerLoad} */
export async function load({ cookies }) {
	const user = await db.getUserFromSession(cookies.get('sessionid'));
	return { user };
}

/** @type {import('./$types').Actions} */
export const actions = {
	login: async ({ cookies, request }) => {
		const data = await request.formData();
		const email = data.get('email');
		const password = data.get('password');

		const user = await db.getUser(email);
		cookies.set('sessionid', await db.createSession(user), { path: '/' });

		return { success: true };
	},
	register: async (event) => {
		// TODO register the user
	}
};
// src/routes/login/+page.svelte
<script>
	/** @type {import('./$types').PageData} */
	export let data;

	/** @type {import('./$types').ActionData} */
	export let form;
</script>

{#if form?.success}
	<!-- this message is ephemeral; it exists because the page was rendered in
		   response to a form submission. it will vanish if the user reloads -->
	<p>Successfully logged in! Welcome back, {data.user.name}</p>
{/if}

Validation errors

無効なデータのためにリクエストを処理できなかった場合、バリデーションエラーを、以前に送信されたフォームの値とともにユーザーに返すことができます。これにより、ユーザーは再試行することができます。fail関数を使用すると、HTTPステータスコード(バリデーションエラーの場合は通常400または422)をデータと一緒に返すことができます。このステータスコードは$page.statusを通じて、データはformを通じて利用可能になります。

// src/routes/login/+page.server.js
import { fail } from '@sveltejs/kit';

/** @type {import('./$types').Actions} */
export const actions = {
	login: async ({ cookies, request }) => {
		const data = await request.formData();
		const email = data.get('email');
		const password = data.get('password');

		if (!email) {
			return fail(400, { email, missing: true });
		}

		const user = await db.getUser(email);

		if (!user || user.password !== hash(password)) {
			return fail(400, { email, incorrect: true });
		}

		cookies.set('sessionid', await db.createSession(user), { path: '/' });

		return { success: true };
	},
	register: async (event) => {
		// TODO register the user
	}
};

予防措置として、メールはページに返されるだけであり、パスワードは返されないことに注意してください。

src/routes/login/+page.svelte
<form method="POST" action="?/login">
	{#if form?.missing}<p class="error">The email field is required</p>{/if}
	{#if form?.incorrect}<p class="error">Invalid credentials!</p>{/if}
	<label>
		Email
		<input name="email" type="email" value={form?.email ?? ''}>
	</label>
	<label>
		Password
		<input name="password" type="password">
	</label>
	<button>Log in</button>
	<button formaction="?/register">Register</button>
</form>

返されるデータはJSONとしてシリアライズ可能でなければなりません。それ以外の構造は完全に自由です。例えば、ページに複数のフォームがある場合、返されるformデータがどの<form>を参照しているかを、idプロパティなどを使って区別することができます。

リダイレクト

リダイレクト (およびエラー) はロード時とまったく同じように機能します。

src/routes/login/+page.server.js
import { fail, redirect } from '@sveltejs/kit';

/** @type {import('./$types').Actions} */
export const actions = {
	login: async ({ cookies, request, url }) => {
		const data = await request.formData();
		const email = data.get('email');
		const password = data.get('password');

		const user = await db.getUser(email);
		if (!user) {
			return fail(400, { email, missing: true });
		}

		if (user.password !== hash(password)) {
			return fail(400, { email, incorrect: true });
		}

		cookies.set('sessionid', await db.createSession(user), { path: '/' });

		if (url.searchParams.has('redirectTo')) {
			redirect(303, url.searchParams.get('redirectTo'));
		}

		return { success: true };
	},
	register: async (event) => {
		// TODO register the user
	}
};

おわりに

今日は、 SvelteKitでのフォームアクションについて解説しました。

よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました