Inertia permite crear interfaces con React usando rutas y controladores de Laravel, sin mantener una API separada.
Bienvenido al desarrollo web moderno. Hasta ahora, hemos usado Blade para renderizar el HTML. Blade es fantástico, pero a veces necesitas esa interactividad instantánea “tipo App” (sin recargas de página) que ofrecen frameworks como React, Vue o Svelte.
La forma tradicional de hacer esto era separar tu proyecto en dos:
- Backend API (Laravel): Solo envía JSON.
- Frontend SPA (React): Una aplicación separada que consume el JSON.
Separar ambos proyectos sigue siendo válido, pero Inertia.js ofrece otra opción: construir una SPA manteniendo las rutas y los controladores de Laravel, sin crear una API para cada pantalla.
En este artículo final, vamos a crear un proyecto que usa Laravel como motor y React como carrocería.
La arquitectura: ¿qué es Inertia.js?
Inertia es el “pegamento” entre Laravel y React. Piensa en cómo trabajabas con Blade:
- Blade: El controlador devuelve
view('perfil', ['user' => $user]). - Inertia: El controlador devuelve
Inertia::render('Perfil', ['user' => $user]).
El patrón se parece mucho. En la primera visita Inertia entrega el documento inicial; en las navegaciones posteriores intercambia los datos de la página y React actualiza el componente sin una recarga completa del documento.
Requisitos
Para este ejercicio, además de PHP y Composer, necesitas tener instalado Node.js en tu ordenador (ya que React se compila con JavaScript).
Comprueba que las herramientas responden desde la terminal con php -v, composer --version y node -v. Usa una versión LTS de Node compatible con las dependencias del proyecto.
Crear un proyecto con el starter kit de React
Instala el CLI oficial y crea el proyecto:
composer global require laravel/installer
laravel new mi-app-reactCuando el instalador pregunte por el starter kit, selecciona React. El proyecto actual incluye Inertia, React, TypeScript, Tailwind y Vite.
Después instala los recursos y arranca el entorno:
cd mi-app-react
npm install
npm run build
composer run devEntra en http://localhost:8000. composer run dev coordina el servidor y el proceso de desarrollo de los recursos.
Pasar datos de PHP a React
Vamos a ver cómo se pasan los datos del servidor al cliente. Vamos a modificar la página de inicio.
La ruta y el controlador (PHP)
Abre routes/web.php. Verás algo nuevo:
use Illuminate\Support\Facades\Route;
use Inertia\Inertia; // <--- Importante
Route::get('/', function () {
// En lugar de view(), usamos Inertia::render()
// 1er parámetro: nombre del archivo en resources/js/pages
// 2do parámetro: Datos (Props) para React
return Inertia::render('demo', [
'phpVersion' => PHP_VERSION,
'nombreUsuario' => 'Luis',
]);
});El componente de React
Los componentes de página están en resources/js/pages. Crea resources/js/pages/demo.tsx y usa el mismo nombre en Inertia::render('demo', ...).
Si sabes un poco de React, esto te resultará familiar. Si no, fíjate en cómo recibimos los datos.
import { Head } from '@inertiajs/react';
type DemoProps = {
phpVersion: string;
nombreUsuario: string;
};
export default function Demo({ phpVersion, nombreUsuario }: DemoProps) {
return (
<>
<Head title="Bienvenido" />
<div className="flex justify-center items-center h-screen bg-gray-100">
<div className="text-center p-10 bg-white shadow-xl rounded-lg">
<h1 className="text-4xl font-bold text-blue-600 mb-4">
¡Hola, {nombreUsuario}!
</h1>
<p className="text-gray-700 text-lg">
Tu Laravel está corriendo con PHP v{phpVersion}
</p>
<button className="mt-6 px-4 py-2 bg-black text-white rounded hover:bg-gray-800 transition">
Botón React Interactivo
</button>
</div>
</div>
</>
);
}Al guardar el archivo, Vite actualizará el navegador mientras composer run dev siga en ejecución.
Crear un contador con estado de React
Para demostrar que esto es una app interactiva real, vamos a añadir un contador en React que no necesita llamar al servidor para funcionar.
Edita demo.tsx:
- Importa el hook
useStatede React al principio:import { useState } from 'react'; - Dentro de la función, antes del
return:
const [contador, setContador] = useState(0);- Modifica el botón en el HTML (JSX):
<button
onClick={() => setContador(contador + 1)}
className="mt-6 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Has hecho clic {contador} veces
</button>Pruébalo. El contador sube instantáneamente. Es JavaScript puro ejecutándose en el navegador, pero servido desde tu proyecto Laravel.
¿Y si prefiero Vue.js?
La belleza de este sistema es que el Backend (Laravel) no cambia. Si prefieres Vue:
- Al ejecutar
laravel new, eliges Vue en lugar de React. - Tus rutas siguen usando
Inertia::render(). - Tus componentes de página serán
.vueen lugar de.tsx.
Ejemplo en Vue (Welcome.vue):
<script setup>
defineProps({ nombreUsuario: String });
</script>
<template>
<h1>Hola, {{ nombreUsuario }}</h1>
</template>Laravel también ofrece un starter kit oficial para Svelte, manteniendo la misma forma de trabajar con rutas y controladores.