Laravel×React Inertiaを使ってフォーム変更時に画面遷移の確認ダイアログを簡単に実装する
公開: 2023-10-25
更新: 2023-10-25
はじめに
Laravel, Reactでユーザーの登録機能を作っています。
登録フォーム画面を開いた時「やっぱりキャンセルして前の画面に戻りたい」といった状況のためにキャンセルボタンを実装しようと思いました。
この時、フォームに入力・変更がある場合はページ遷移前に本当にキャンセルするか確認を促すようにします。Inertiaを使ってかなり簡単にできたためメモします。
ユーザー登録画面route('users.create')
で、「キャンセルボタン」を押した時に登録画面から一覧画面route('users.index')
に戻す処理を実装する例です。
// 実装コード概要
import { Link, useForm } from "@inertiajs/react";
const { isDirty } = useForm({ ... })
function handleBeforeLeave() {
if (isDirty) {
return confirm('入力内容が破棄されますがよろしいですか?');
}
return true;
};
return (
<>
<Link
onBefore={handleBeforeLeave}
href={route('users.index')}
className="btn btn-secondary"
>
キャンセル
</Link>
以下省略...
</>
);
処理の説明
userFormのisDirty
useForm
のisDirty
プロパティを使います。参考: Forms - Inertia.js
isDirty
はフォームに変更がある場合にtrue
を返します。
import { useForm } from '@inertiajs/react'
const { isDirty } = useForm({ ... })
LinkコンポーネントのonBefore
Inertiaの<Link>
コンポーネントを使います。参考: Links - Inertia.js
Link
が持っているプロパティの一つonBefore
にコールバック関数を渡して、true
の時のみリンク処理を続行、false
の時は処理を中断させます。
import { Link } from "@inertiajs/react";
<Link
onBefore={handleBeforeLeave}
href={route('users.index')}
className="btn btn-secondary"
>
(route
メソッドはZiggyパッケージをインストールしてJSXファイルで使えるようにしています)
コールバック関数の定義
onBefore
に渡すコールバック関数を定義します。isDirty
により、フォームに変更がある場合のみconfirm
で確認ダイアログを表示し、ここでキャンセルした時だけfalse
が返るためonBefore
によってLinkの処理が中断されます。
function handleBeforeLeave() {
if (isDirty) {
return confirm('入力内容が破棄されますがよろしいですか?');
}
return true;
};
実装例
ユーザー登録フォームCreate.jsx
の該当部分抜粋です。
// resources/js/Pages/User/Create.jsx
import { useEffect } from 'react';
import AppLayout from '@/Layouts/AppLayout';
import { Link, useForm } from "@inertiajs/react";
export default function Create() {
const { data, setData, post, processing, errors, reset, isDirty } = useForm({
name: '',
email: '',
password: '',
password_confirmation: '',
});
useEffect(() => {
return () => {
reset('password', 'password_confirmation');
};
}, []);
function submit(e) {
e.preventDefault();
post(route('users.store'));
};
function handleBeforeLeave() {
if (isDirty) {
return confirm('入力内容が破棄されますがよろしいですか?');
}
return true;
};
return (
<AppLayout>
<h1>ユーザー登録</h1>
<div className="form-action-bar">
<Link
onBefore={handleBeforeLeave}
href={route('users.index')}
className="btn btn-secondary"
>
キャンセル
</Link>
<button
type="submit"
form="userCreateForm"
className="btn btn-primary"
disabled={processing}
>
登録
</button>
</div>
<form id="userCreateForm" onSubmit={submit}>
... 以下省略