Back to Course |
React.js + Inertia in Laravel 11: From Scratch

Create Post Form: Component and Submit in SPA

In the last lesson, we stopped before creating the login form. But, to create the login form, we need to get familiar with forms and how they work in Inertia in general.

We will do that based on another form: we will create the "Add new post" form and apply that form to the login form in the following lessons a bit later.


Preparation: React Component, Route and Controller

First, we need to create a React component where the form will be, then the route, and then we need to submit the form.

**resources/js/Pages/Posts/Create.jsx:

import AppLayout from '../../Layouts/AppLayout.jsx';
import { Head, Link, useForm } from '@inertiajs/react';
 
export default function CreatePost() {
return (
<AppLayout>
 
<Head title="New Post" />
<div>
Form here
</div>
</AppLayout>
);
}

In the routes, we will transform the post route into a resource.

routes/web.php:

Route::get('posts', [PostController::class, 'index'])->name('posts.index');
Route::resource('posts', PostController::class);
Route::inertia('about', 'About')->name('about');
Route::inertia('login', 'Pages/Login')->name('login');

In the PostController we need to return Inertia in the create() method.

app/Http/Controllers/PostController.php:

use Inertia\Inertia;
use Inertia\Response;
 
class PostController extends Controller
{
//
 
public function create(): Response
{
return Inertia::render('Posts/Create');
}
}

After visiting the posts/create page, we see the page with the Form here text.


Add Link to the Form

Next, add a link above the posts table to the create post page.

resources/js/Pages/Posts/Index.jsx:

import AppLayout from '../../Layouts/AppLayout.jsx';
import { Head } from '@inertiajs/react';
import { Head, Link } from '@inertiajs/react';
 
export default function PostsIndex({ posts }) {
return (
<AppLayout>
<Head>
<title>Posts</title>
</Head>
 
<div>
<Link href={route('posts.create')} className="mb-4 inline-block rounded-md bg-blue-500 px-4 py-3 text-xs font-semibold uppercase tracking-widest text-white shadow-sm">
Add new post
</Link>
 
<table className="min-w-full divide-y divide-gray-200 border">
// ...
);
};


Build The Form

Now, let's add the form.

resources/js/Pages/Posts/Create.jsx:

import AppLayout from '../../Layouts/AppLayout.jsx';
import { Head, Link } from '@inertiajs/react';
 
export default function CreatePost() {
return (
<AppLayout>
<Head title="New Post" />
 
<div>
Form here
<form onSubmit={submit}>
<div>
<label htmlFor="title" className="block text-sm font-medium text-gray-700">Title</label>
<input onChange={(e) => setData('title', e.target.value)} type="text" id="title" className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" />
</div>
<div className="mt-4">
<label htmlFor="content" className="block text-sm font-medium text-gray-700">Content</label>
<textarea onChange={(e) => setData('content', e.target.value)} type="text" id="content" className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"></textarea>
</div>
<div className="mt-4 py-4 space-x-2">
<button type="submit" className="inline-block rounded-md bg-blue-500 px-4 py-3 text-xs font-semibold uppercase tracking-widest text-white shadow-sm">
Save post
</button>
<Link href={route('posts.index')} className="inline-block rounded-md border border-gray-300 px-4 py-3 text-xs font-semibold uppercase tracking-widest shadow-sm">
Cancel
</Link>
</div>
</form>
</div>
</AppLayout>
);
}

In the form, we have a submit action where we will add the route later.

Inertia has a form helper that helps with the forms. First, we import the useForm and then use it to define and set the form fields.

resources/js/Pages/Posts/Create.jsx:

import AppLayout from '../../Layouts/AppLayout.jsx';
import { Head, Link } from '@inertiajs/react';
import { Head, Link, useForm } from '@inertiajs/react';
 
export default function CreatePost() {
const { data, setData, post, processing, errors, reset } = useForm({
title: '',
content: '',
});
 
return (
// ...
);
}

Now we can see the create form.


Submitting the Form

Before submitting the form in the front-end, let's add the back-end part in the Controller.

app/Http/Controllers/PostController.php:

use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
 
class PostController extends Controller
{
// ...
 
public function store(Request $request): RedirectResponse
{
Post::create([
'title' => $request->input('title'),
'content' => $request->input('content'),
]);
 
return redirect()->route('posts.index');
}
}

To submit the form in the React component, we can use the post function from the Inertia form helper and send the post by providing the route.

resources/js/Pages/Posts/Create.jsx:

import AppLayout from '../../Layouts/AppLayout.jsx';
import { Head, Link, useForm } from '@inertiajs/react';
 
export default function CreatePost() {
const { data, setData, post, processing, errors, reset } = useForm({
title: '',
content: '',
});
 
const submit = (e) => {
e.preventDefault();
 
post(route('posts.store'));
};
 
return (
// ...
);
}

Inertia's beauty is that we made a Laravel redirect after creating the post. Still, Inertia catches the redirect and keeps the SPA feeling by loading only the posts React component without loading all the assets.