はじめに
前回はInertiaの基本的な内容について書いてみました。今回はもう少し実践的内容という事で、Inertiaで用意しているフォームリクエスト周りの機能について紹介したいと思います。
前回同様に、Laravel+Reactの組み合わせです。
フォームヘルパー
Reactでフォームリクエストを実装する際は、useStateフックを使用して実装する事が多いと思いますが、Inertiaではフォームに特化したuseFormフックを使う事が出来ます。
Laravel Sailに含まれるサンプルログイン画面を参考にuseFormフックの使い方を見たいと思います。
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 | export default function Login({status, canResetPassword}) { // useStateフックをラップしたuseForm const {data, setData, post, processing, errors, reset} = useForm({ email: '', password: '', remember: '', }); useEffect(() => { return () => { reset('password'); }; }, []); const onHandleChange = (event) => { setData(event.target.name, event.target.type === 'checkbox' ? event.target.checked : event.target.value); }; const submit = (e) => { e.preventDefault(); post(route('login')); }; return ( <GuestLayout> <Head title="Log in"/> <form onSubmit={submit}> <div> <InputLabel forInput="email" value="Email"/> <TextInput id="email" type="email" name="email" value={data.email} className="mt-1 block w-full" autoComplete="username" isFocused={true} handleChange={onHandleChange}/> <InputError message={errors.email} className="mt-2"/> </div> <div className="mt-4"> <InputLabel forInput="password" value="Password"/> <TextInput id="password" type="password" name="password" value={data.password} className="mt-1 block w-full" autoComplete="current-password" handleChange={onHandleChange}/> <InputError message={errors.password} className="mt-2"/> </div> <div className="block mt-4"> <label className="flex items-center"> <Checkbox name="remember" value={data.remember} handleChange={onHandleChange}/> <span className="ml-2 text-sm text-gray-600">Remember me</span> </label> </div> <div className="flex items-center justify-end mt-4"> <Link href={route('password.request')} className="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"> Forgot your password? </Link> <PrimaryButton className="ml-4" processing={processing}> Log in </PrimaryButton> </div> </form> </GuestLayout> ); } |
ポイント
上記例では、useFormで以下のような関数や値を使用しています。一般的なフォーム送信に必要な事項揃っているかと思います。
- useState同様に、
useForm()
の引数に初期値を設定する。ここでは、email、password、rememberの3つでそれぞれ空白となっています。 - 値更新の際もuseState同様に、
setData
で更新する -
post()
関数だけでフォームデータをPOST通信しています。他に、get、put、delete、patchも用意されています。 - 通信中かどうかを
processing
で判別出来ます。ここでは、通信中はログインボタンをdisableにして複数回クリック出来ないようにしています。 - Controller側でバリデーションエラーが出た場合、フィールドとエラーメッセージが
errors
に含まれます。ここでは、InputErrorコンポーネントに渡してエラーの場合のみ、メッセージを赤字表示しています -
reset
で値をデフォルト値に戻す事が出来ます。。フィールド名を含めるとそのフィールドが消去され、何も指定しないと全ての値がデフォルト値に戻るようです。
他機能
他にも例便利な関数や値があるので一部紹介すると
transform
関数を使い、送信前のフォームデータを編集する事が出来ます。
1 2 3 4 5 | transform((data) => { // チェックボックスがチェックされていたら、trueの代わりに文字列の`on`を代入 data.remember = data.remember ? 'on' : ''; return data; }) |
フォーム送信が成否を判別する
wasSuccessful
や
recentlySuccessful
の値を見て通信結果を表示する事が出来ます。
通信が成功するとそれぞれtrueの値がセットされます。
recentlySuccessful
は2秒間だけtrueがセットされるので、フラッシュメッセージ表示に利用出来ます。
1 2 | <span>{wasSuccessful ? '通信が成功しました' : ''}</span> <span>{recentlySuccessful ? '通信が成功しました(2秒間だけ表示される)' : ''}</span> |
ローディング表示
Progressライブラリのラッパーが用意されています。
app.jsxファイルの設定で表示内容を変更する事が出来ます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | createInertiaApp({ progress: { // プログレスバーが表示されるまでの時間(ミリ秒) delay: 250, // プログレスバー色 color: '#29d', // Default NProgress stylesを使用するか includeCSS: true, // グルグル表示を行うかどうか showSpinner: false, }, // ... }) |
デフォルトの状態だとグルグル表示が画面右上に小さく表示されるだけなので、app.cssファイルにCSSを追加して表示を変更した方が良いかと思います。下は、画面中央に100pxサイズで表示する際の例です。
1 2 3 4 5 6 7 8 9 10 11 | .nprogress-busy #nprogress { @apply bg-gray-200 opacity-50 top-0 left-0 fixed w-full h-full } .nprogress-busy #nprogress .spinner { @apply absolute top-1/2 right-1/2 } .nprogress-busy #nprogress .spinner-icon { @apply w-[100px] h-[100px] } |
さいごに
useFormを利用する事でフォームデータの管理からフラッシュメッセージ表示まで一通りの事を簡潔に実装出来そうです。機会があれば使ってみてください。