inertia.jsのformをちゃんとやる

大前提

inertia.jsではformヘルパーを使う事がほぼほぼだ。これはlaravelとの相性がバツグンに作られている。たとえばerrorを掴まえたりとかそういうような事はほぼできてしまう。なお、これを使う場合はformタグを使う。まあちょっと例を見ていこう。

一番シンプルなフォーム

import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'
import { Head, router } from '@inertiajs/react'
import { useState } from 'react'
import PrimaryButton from '@/Components/PrimaryButton';

export default function DemoForms({ auth }) {

  const submit = (e) => {
    e.preventDefault();
  };

  return (
    <AuthenticatedLayout
      user={auth.user}
      header={
        <h2 className="font-semibold text-xl text-gray-800 leading-tight">
          DemoForm
        </h2>
      }
    >
      <Head title="DemoForm" />

      <div className="py-12">
        <div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
          <div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
            <div className="p-6 text-gray-900">
              <form onSubmit={submit}>
                 <PrimaryButton>Send</PrimaryButton>
              </form>
            </div>
          </div>
        </div>
      </div>
    </AuthenticatedLayout>
  )
}

ここでは便宜的にPrimaryButton コンポーネントを使ったが別に<button>でもいい。見た目の問題だ。これにより以下のような見た目が提供されるだろう。


ボタンのみのform

パーツを置いていく

といってもここではinput type="text"のみをおく。あとpostとかもろもろ付けたので全文載せておく

import { useState } from 'react'
import PrimaryButton from '@/Components/PrimaryButton';

export default function DemoForms({ auth }) {

  const { post } = useForm();

  const submit = (e) => {
    e.preventDefault();
    post(route('demoforms.store'));
  };

  return (
    <AuthenticatedLayout
      user={auth.user}
      header={
        <h2 className="font-semibold text-xl text-gray-800 leading-tight">
          DemoForm
        </h2>
      }
    >
      <Head title="DemoForm" />

      <div className="py-12">
        <div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
          <div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
            <div className="p-6 text-gray-900">
              <form onSubmit={submit}>
                <input type="text" name="message" />
                <PrimaryButton>Send</PrimaryButton>
              </form>
            </div>
          </div>
        </div>
      </div>
    </AuthenticatedLayout>
  )
}

さて、これで


こんなのを入力でき、かつsubmitの送信先を 

    post(route('demoforms.store'));

このrouteにした。これはlaravelのrouteと同じだからちゃんと設定しておく。laravelのcontrollerでは以下のようにとりあえずrequest dumpして終わる

    public function store(Request $request)
    {
        dd($request->all());
    }

そうすると「あああ」とか入力したdumpは

となる、要するに空というわけだ。

dataとsetDataの使用

以下のように定義する

  const { post } = useForm({
    message: '',
  });

これで送信すると少なくとも

このようにmessageキーは付くようになった。実際にこのdataに値をsetするのがsetDataであり、以下のように使う

  const { post, setData } = useForm({
    message: '',
  });

で、formでは

              <form onSubmit={submit}>
                <input type="text" name="message"
                onChange={e => setData('message', e.target.value)}
              />
                <PrimaryButton>Send</PrimaryButton>
              </form>

こんな風にして使う、すると

このようにレシーブできるはずだ。

フォーム完了の処理

本来は

    public function store(Request $request)
    {
        dd($request->all());
    }

このddでDBに保存したりするだろうが、ここでは行わない。とりあえず何かやって戻すのが、inertia.jsの基本であり、これは従来型のhttpのpostと同じノリだろう。

    public function store(Request $request): RedirectResponse
    {
         // データー更新処理
         return redirect(route('demoforms.index'));
    }

これでデーターが更新されていくはずだ(本来は)

ただ、ここでSendを押しても何も変わらない

これは実際に画面遷移を行っていないからであり、この状態だと何なんだかよくわからんので、処理が成功した時はonSuccessを走らせるとよい。

  const submit = (e) => {
    e.preventDefault();
    post(route('demoforms.store'),  { onSuccess: () => alert("ok") } );
  };

resetとdata

実際のところalertを出しても意味がないからformを抹消するとする。これはresetをuseFormから呼び出す

  const { post, setData, reset } = useForm({
    message: '',
  });

  const submit = (e) => {
    e.preventDefault();
    post(route('demoforms.store'),  { onSuccess: () => reset() } );
  };

じゃあこれでresetされんのか?

              <form onSubmit={submit}>
                <input type="text" name="message"
                onChange={e => setData('message', e.target.value)}
              />
                <PrimaryButton>Send</PrimaryButton>
              </form>

というとリセットされない。なぜならこのresetはuseFormのdata部分を空にするという挙動だからであーる。つまりvalueをuseFormのdataに合わせる必要がある。やってみよう。

dataにアクセスする場合はdata変数も呼びこまないといけない。

  const { post, setData, reset, data } = useForm({
    message: '',
  });

これにより

              <form onSubmit={submit}>
                <input type="text" value={data.message}
                  onChange={e => setData('message', e.target.value)}
                />
                <PrimaryButton>Send</PrimaryButton>
              </form>

このようにvalueを正しくdataからひっぱってこれるようになり、resetが機能するようになる。つまりresetとはuseFormのdataを抹消することともいえる。

その他の便利なメソッド郡

processing

これはやはり便利がよくて、以下のように通常利用される

  const { post, setData, reset, data, processing } = useForm({
    message: '',
  });

これで代入しておいての

              <form onSubmit={submit}>
                <input type="text" value={data.message}
                  onChange={e => setData('message', e.target.value)}
                />
                <PrimaryButton disabled={processing}>Send</PrimaryButton>
              </form>

こんな感じ。これはform送信中はtrueになるというもので、たとえば長い処理をシュミレートする

    public function store(Request $request): RedirectResponse
    {
        sleep(5);
        return redirect(route('demoforms.index'));
    }

このような時、とりわけ威力を発揮するだろう

この記事が気に入ったらサポートをしてみませんか?