Inertia + React sous Laravel 12 : retour d'expérience

Laravel 12 intègre un starter kit React basé sur Inertia.js. Cette stack offre le meilleur des deux mondes : routing et controllers côté serveur, UI réactive côté client. Voici mon retour après plusieurs projets en production.

C'est quoi Inertia ?

Inertia n'est pas un framework frontend. C'est un adaptateur qui connecte votre backend Laravel à votre frontend React (ou Vue, Svelte). Pas d'API REST à construire, pas de gestion d'état complexe.

Le principe

Vous écrivez vos controllers Laravel normalement, mais au lieu de retourner une vue Blade, vous retournez un composant React avec ses props. Inertia gère la navigation SPA-like sans rechargement de page.

                
app/Http/Controllers/UserController.php
use Inertia\Inertia; class UserController extends Controller { public function show(User $user): Response { return Inertia::render('Users/Show', [ 'user' => $user, 'posts' => $user->posts()->latest()->get(), ]); } }
                
resources/js/Pages/Users/Show.jsx
import Layout from '@/Layouts/Authenticated'; import { Head, Link } from '@inertiajs/react'; export default function Show({ user, posts }) { return ( <Layout> <Head title={user.name} /> <h1>{user.name}</h1> <ul> {posts.map(post => ( <li key={post.id}> <Link href={`/posts/${post.id}`}> {post.title} </Link> </li> ))} </ul> </Layout> ); }

Setup avec Laravel 12

Laravel 12 propose un starter kit React officiel via laravel new.

                
Terminal
# Nouveau projet avec le starter React laravel new my-app # Choisir "React with Inertia" dans le menu interactif # Ou directement : laravel new my-app --stack=react

Le starter inclut tout : authentification, layouts, TypeScript (optionnel), Tailwind CSS.

Structure des fichiers

                
Structure Inertia/React
resources/js/ ├── app.jsx # Point d'entrée ├── Pages/ │ ├── Dashboard.jsx │ ├── Auth/ │ │ ├── Login.jsx │ │ └── Register.jsx │ └── Users/ │ ├── Index.jsx │ └── Show.jsx ├── Components/ │ ├── Button.jsx │ └── Input.jsx └── Layouts/ ├── Authenticated.jsx └── Guest.jsx

Configuration du point d'entrée

                
resources/js/app.jsx
import { createInertiaApp } from '@inertiajs/react'; import { createRoot } from 'react-dom/client'; createInertiaApp({ resolve: name => { const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true }); return pages[`./Pages/${name}.jsx`]; }, setup({ el, App, props }) { createRoot(el).render(<App {...props} />); }, });

Partage de données globales

Certaines données doivent être disponibles sur toutes les pages : utilisateur connecté, permissions, flash messages. Le middleware HandleInertiaRequests gère ça.

                
app/Http/Middleware/HandleInertiaRequests.php
class HandleInertiaRequests extends Middleware { public function share(Request $request): array { return [ ...parent::share($request), 'auth' => [ 'user' => $request->user(), 'permissions' => $request->user()?->getAllPermissions() ->pluck('name'), ], 'flash' => [ 'success' => session('success'), 'error' => session('error'), ], ]; } }
                
Accès côté React
import { usePage } from '@inertiajs/react'; export default function Dashboard() { const { auth, flash } = usePage().props; return ( <div> {flash.success && ( <div className="alert-success">{flash.success}</div> )} <p>Bienvenue, {auth.user.name}</p> </div> ); }

Formulaires avec Inertia

Le hook useForm simplifie la gestion des formulaires : état, validation, soumission.

                
resources/js/Pages/Posts/Create.jsx
import { useForm } from '@inertiajs/react'; export default function Create() { const { data, setData, post, processing, errors } = useForm({ title: '', content: '', }); function submit(e) { e.preventDefault(); post('/posts'); } return ( <form onSubmit={submit}> <div> <input type="text" value={data.title} onChange={e => setData('title', e.target.value)} /> {errors.title && <span>{errors.title}</span>} </div> <div> <textarea value={data.content} onChange={e => setData('content', e.target.value)} /> {errors.content && <span>{errors.content}</span>} </div> <button type="submit" disabled={processing}> Créer </button> </form> ); }

Les erreurs de validation Laravel sont automatiquement disponibles dans errors.

Server-Side Rendering (SSR)

Pour le SEO et les performances perçues, Inertia supporte le SSR. Laravel 12 le configure automatiquement.

                
Terminal
# Build avec SSR npm run build:ssr # Lancer le serveur SSR en dev php artisan inertia:start-ssr # Ou tout en un composer dev:ssr
                
resources/js/ssr.jsx
import { createInertiaApp } from '@inertiajs/react'; import createServer from '@inertiajs/react/server'; import ReactDOMServer from 'react-dom/server'; createServer(page => createInertiaApp({ page, render: ReactDOMServer.renderToString, resolve: name => { const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true }); return pages[`./Pages/${name}.jsx`]; }, setup: ({ App, props }) => <App {...props} />, }), );

Quand activer le SSR

Activez-le si le SEO est important (landing pages, blog, e-commerce public).
Pas nécessaire pour les dashboards et apps internes où tout est derrière auth.

Inertia vs Livewire : lequel choisir ?

Les deux sont des solutions officielles Laravel. Le choix dépend de votre contexte.

Choisir Inertia + React quand :

Choisir Livewire quand :

Mon avis : Pour les apps métier complexes avec beaucoup d'interactivité, Inertia + React offre plus de flexibilité. Pour les CRUD et dashboards, Livewire est souvent plus productif.

Patterns utiles

Layouts persistants

Évitez de re-render le layout entier à chaque navigation.

                
Layout persistant
import AppLayout from '@/Layouts/AppLayout'; function Dashboard({ stats }) { return ( <div> <h1>Dashboard</h1> <div>Active Users: {stats.activeUsers}</div> </div> ); } // Le layout persiste entre les navigations Dashboard.layout = page => <AppLayout children={page} />; export default Dashboard;

Partial reloads

Rechargez seulement certaines props pour optimiser les performances.

                
Partial reload
import { router } from '@inertiajs/react'; // Recharge seulement 'notifications' sans toucher au reste router.reload({ only: ['notifications'] }); // Avec polling automatique setInterval(() => { router.reload({ only: ['notifications'] }); }, 30000);

Preserving state

                
Préserver le scroll et l'état
import { Link } from '@inertiajs/react'; // Préserve la position de scroll <Link href="/users" preserveScroll>Users</Link> // Préserve l'état local du composant <Link href="/users" preserveState>Users</Link>

Pièges à éviter

Ne pas exposer trop de données

Les props sont sérialisées en JSON et envoyées au client. N'envoyez pas de données sensibles (mots de passe hashés, tokens, données privées d'autres users).

                
Filtrer les données sensibles
// Mauvais : expose tout le user return Inertia::render('Profile', [ 'user' => $user, // Inclut remember_token, etc. ]); // Bon : sélectionne les champs return Inertia::render('Profile', [ 'user' => $user->only(['id', 'name', 'email', 'avatar']), ]); // Mieux : utilisez une API Resource return Inertia::render('Profile', [ 'user' => new UserResource($user), ]);

Attention aux relations non chargées

                
N+1 avec Inertia
// Mauvais : N+1 lors de la sérialisation return Inertia::render('Posts/Index', [ 'posts' => Post::all(), // author sera lazy-loaded ]); // Bon : eager load return Inertia::render('Posts/Index', [ 'posts' => Post::with('author')->get(), ]);

Conclusion

Inertia + React est une excellente stack pour les applications Laravel modernes. Elle combine la productivité du développement server-side avec la richesse de l'écosystème React.

Points clés à retenir :

Besoin d'aide sur votre projet ?

Je peux vous accompagner dans le développement ou l'optimisation de votre application.

Me contacter