ReactJS and Laravel are among the most popular tools for modern web development. Combining React’s dynamic user interfaces with Laravel’s robust backend makes for a highly efficient and scalable stack. Inertia.js acts as the glue that connects the two, offering a smooth way to build single-page applications (SPAs) without sacrificing the simplicity of server-side routing. This guide will walk you through setting up this stack from scratch, creating a CRUD application with file uploads, and enabling advanced features like server-side rendering (SSR).
Why Use React, Inertia.js, and Laravel Together?
- Benefits:
1- Seamless SPA Development: Inertia allows you to build SPAs without an API layer, reducing boilerplate and simplifying development.
2- Dynamic UI with React: React’s component-based architecture makes building complex user interfaces a breeze.
3- Laravel’s Backend Strength: Laravel’s robust ecosystem provides tools like Eloquent ORM, routing, and task scheduling.
4- Enhanced Developer Experience: Inertia bridges the gap between client-side React and server-side Laravel, enabling effortless data sharing and page navigation.
5- Flexibility with SSR: Inertia’s SSR support ensures faster page loads and improved SEO.
Setting Up Your Environment
Before we dive into building the application, ensure you have the following installed:
Node.js: Latest stable version.
Composer: To manage PHP dependencies.
PHP 8.2+: Required for Laravel 11.
Laravel Installer: Optional but recommended.
Database: MySQL or PostgreSQL.
Step 1: Create a New Laravel Project
Run the following command to create a new Laravel 11 project:
composer create-project laravel/laravel laravel-inertia-react --prefer-dist
cd laravel-inertia-react
Step 2: Install Inertia.js
Inertia.js has both a server-side adapter for Laravel and client-side adapters for JavaScript frameworks like React.
Install the Laravel Adapter:
composer require inertiajs/inertia-laravel
Install the React Client Adapter:
npm install @inertiajs/react
Step 3: Configure Inertia Middleware
In Laravel 11, Inertia middleware is automatically registered. However, you may customize the middleware if necessary by editing app/Http/Middleware/HandleInertiaRequests.php
.
Make sure the middleware is included in the bootstrap/app.php
withMiddleware method:
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
\App\Http\Middleware\HandleInertiaRequests::class,
]);
})
Step 4: Install React and Vite
Laravel uses Vite for modern frontend tooling. Install React and its dependencies:
npm install react react-dom
npm install @vitejs/plugin-react
Update your vite.config.js
:
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
laravel({
input: ['resources/js/app.jsx'],
refresh: true,
}),
react(),
],
});
Create the entry file at resources/js/app.jsx
:
import React from 'react';
import { createRoot } from 'react-dom/client';
import { createInertiaApp } from '@inertiajs/react';
createInertiaApp({
resolve: name => import(`./Pages/${name}`),
setup({ el, App, props }) {
const root = createRoot(el);
root.render(<App {...props} />);
},
});
Update your resources/views/app.blade.php
layout:
<!DOCTYPE html>
<html>
<head>
@vite('resources/js/app.jsx')
</head>
<body>
@inertia
</body>
</html>
Step 5: Enable SSR
Install the SSR adapter for Inertia: Server-side rendering (SSR) is particularly beneficial in this stack as it improves SEO by providing search engines with fully-rendered pages. Additionally, SSR enhances initial load times for users, creating a smoother experience.
npm install @inertiajs/server
Update your vite.config.js
to enable SSR:
ssr: {
noExternal: ['@inertiajs/server']
},
Run the server:
php artisan serve
npm run dev
Building a CRUD Application
Let’s create a CRUD (Create, Read, Update, Delete) application to manage "Posts," complete with file uploads and validation. CRUD operations form the backbone of most web applications, enabling essential data management workflows. File uploads are included to demonstrate how to handle media or document uploads, a common feature in modern applications.
Step 1: Create the Database and Models
Update your .env
file with your database credentials. Then, create the migration for the posts
table:
php artisan make:model Post -m
Edit the migration file in database/migrations
:
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->string('file_path')->nullable();
$table->timestamps();
});
}
Run the migration:
php artisan migrate
Step 2: Create a Controller
Generate the controller for posts:
php artisan make:controller PostController
In PostController
, implement CRUD methods:
use App\Models\Post;
use Illuminate\Http\Request;
use Inertia\Inertia;
class PostController extends Controller
{
public function index()
{
return Inertia::render('Posts/Index', [
'posts' => Post::all(),
]);
}
public function create()
{
return Inertia::render('Posts/Create');
}
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
'file' => 'nullable|file',
]);
$filePath = $request->file('file')?->store('uploads', 'public');
Post::create(array_merge($validated, [
'file_path' => $filePath,
]));
return redirect()->route('posts.index');
}
public function edit(Post $post)
{
return Inertia::render('Posts/Edit', [
'post' => $post,
]);
}
public function update(Request $request, Post $post)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
'file' => 'nullable|file',
]);
$filePath = $request->file('file')?->store('uploads', 'public');
$post->update(array_merge($validated, [
'file_path' => $filePath,
]));
return redirect()->route('posts.index');
}
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('posts.index');
}
}
Step 3: Define Routes
Update your routes/web.php
file:
use App\Http\Controllers\PostController;
Route::resource('posts', PostController::class);
Step 4: Create React Pages
resources/js/Pages/Posts/Index.jsx
:
import React from 'react';
import { Link, usePage } from '@inertiajs/react';
export default function Index() {
const { posts } = usePage().props;
return (
<div>
<Link href="/posts/create">Create Post</Link>
<ul>
{posts.map(post => (
<li key={post.id}>
{post.title}
<Link href={`/posts/${post.id}/edit`}>Edit</Link>
</li>
))}
</ul>
</div>
);
}
Other Components
For example, in resources/js/Pages/Posts/Create.jsx
:
import React, { useState } from 'react';
import { useForm } from '@inertiajs/react';
export default function Create() {
const { data, setData, post, errors } = useForm({
title: '',
content: '',
file: null,
});
const handleSubmit = (e) => {
e.preventDefault();
post('/posts');
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Title</label>
<input
type="text"
value={data.title}
onChange={(e) => setData('title', e.target.value)}
/>
{errors.title && <div>{errors.title}</div>}
</div>
<div>
<label>Content</label>
<textarea
value={data.content}
onChange={(e) => setData('content', e.target.value)}
></textarea>
{errors.content && <div>{errors.content}</div>}
</div>
<div>
<label>File</label>
<input
type="file"
onChange={(e) => setData('file', e.target.files[0])}
/>
{errors.file && <div>{errors.file}</div>}
</div>
<button type="submit">Create</button>
</form>
);
}
Similarly, in resources/js/Pages/Posts/Edit.jsx
:
import React, { useState } from 'react';
import { useForm } from '@inertiajs/react';
export default function Edit({ post }) {
const { data, setData, put, errors } = useForm({
title: post.title,
content: post.content,
file: null,
});
const handleSubmit = (e) => {
e.preventDefault();
put(`/posts/${post.id}`);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Title</label>
<input
type="text"
value={data.title}
onChange={(e) => setData('title', e.target.value)}
/>
{errors.title && <div>{errors.title}</div>}
</div>
<div>
<label>Content</label>
<textarea
value={data.content}
onChange={(e) => setData('content', e.target.value)}
></textarea>
{errors.content && <div>{errors.content}</div>}
</div>
<div>
<label>File</label>
<input
type="file"
onChange={(e) => setData('file', e.target.files[0])}
/>
{errors.file && <div>{errors.file}</div>}
</div>
<button type="submit">Update</button>
</form>
);
}
These examples provide basic forms for creating and editing posts, including error handling and file upload support.
Conclusion
This guide demonstrates how to set up a Laravel 11 and ReactJS application using Inertia.js 2. The stack simplifies SPA development, minimizes complexity, and allows for features like SSR. With this foundational setup, you can build dynamic and scalable web applications efficiently.
Top comments (0)