Tutorial: Inertia.js + Laravel – Obtención y guardado de datos
Introducción
Inertia.js es un puente entre tu backend (Laravel) y tu frontend (Vue/React/Svelte) que te permite construir aplicaciones de una sola página (SPA) sin necesidad de crear una API REST ni usar un enrutador del lado del cliente. En lugar de eso, usas las rutas y controladores de Laravel como siempre, pero Inertia se encarga de actualizar la vista (el componente Vue) sin recargar la página completa.
Ventajas principales:
No necesitas construir una API separada.
Mantienes el flujo tradicional de Laravel (rutas, controladores, sesiones, validación).
El frontend se beneficia de la reactividad de Vue sin la complejidad de un SPA puro.
Las redirecciones y validaciones funcionan de forma nativa.
En este tutorial, nos basamos en el ejemplo de una lista de tareas guardada en sesión. Veremos:
Cómo obtener datos (desde el controlador a la vista).
Cómo guardar datos (desde el formulario al controlador).
Comparativa con el enfoque tradicional (sin Inertia) para entender las diferencias.
1. Estructura de archivos del ejemplo
Los archivos que vamos a tocar son:
routes/web.php → Definición de rutas.
app/Http/Controllers/TareaController.php → Lógica del controlador.
resources/js/Pages/Tarea.vue → Componente Vue (la vista).Además, asumimos que tienes un proyecto Laravel con Inertia y Vue 3 instalado (laravel new proyecto --inertia=vue).
2. Obtención de datos (Mostrar la tarea)
Enfoque tradicional (sin Inertia)
En una aplicación Laravel clásica con Blade, para mostrar datos harías algo así:
Controlador:
public function index()
{
$tarea = session('tarea', '');
return view('tarea', compact('tarea'));
}Vista Blade (tarea.blade.php):
<h1>Mi Tarea</h1>
<form method="POST" action="/tarea">
@csrf
<input type="text" name="tarea" value="{{ old('tarea') }}">
<button type="submit">Guardar</button>
</form>
@if ($tarea)
<div><strong>Tarea actual:</strong> {{ $tarea }}</div>
@else
<p>No hay tarea guardada.</p>
@endifEl controlador devuelve una vista Blade con los datos incrustados en el HTML.
La página se renderiza completamente en el servidor y se envía al cliente.
Enfoque con Inertia
Controlador (index):
public function index()
{
$tarea = session('tarea', '');
return Inertia::render('Tarea', [
'tarea' => $tarea
]);
}Componente Vue (Tarea.vue):
<template>
<h1>Mi Tarea</h1>
<!-- Formulario con Inertia -->
<form @submit.prevent="guardarTarea">
<input type="text" v-model="form.tarea" placeholder="Escribe una tarea..." />
<button type="submit">Guardar</button>
</form>
<div v-if="tarea"><strong>Tarea actual:</strong> {{ tarea }}</div>
<p v-else>No hay tarea guardada.</p>
</template>
<script setup>
import { useForm } from '@inertiajs/vue3';
defineProps({
tarea: String
});
const form = useForm({ tarea: '' });
function guardarTarea() {
form.post('/tarea', {
preserveState: true,
onSuccess: () => { form.tarea = ''; }
});
}
</script>Diferencias clave en la obtención de datos:
En lugar de
view(), usamosInertia::render()que recibe el nombre del componente Vue y un array de propiedades (props) que se pasarán al componente.El componente Vue declara las props con
definePropspara recibir los datos del servidor.Inertia serializa las props a JSON y las envía al cliente junto con el componente. Luego, el cliente renderiza el componente con esos datos.
No hay recarga de página: al navegar a una ruta, Inertia intercepta la respuesta y solo actualiza el contenido de la página (el componente) sin recargar el navegador.
Conclusión: La obtención de datos es similar en cuanto a que el controlador obtiene los datos y los pasa a la vista. La diferencia está en que en lugar de una vista Blade, se pasa un componente Vue con props, y la comunicación es mediante JSON en lugar de HTML.
3. Guardado de datos (Enviar tarea)
Enfoque tradicional (sin Inertia)
Controlador (store):
public function store(Request $request)
{
$request->validate(['tarea' => 'required|string|max:255']);
session(['tarea' => $request->tarea]);
return redirect()->route('tarea.index')->with('success', 'Tarea guardada');
}El formulario envía una petición POST tradicional.
El controlador valida, guarda en sesión y redirige a la ruta index.
La redirección hace que el navegador recargue la página y se muestre la nueva tarea.
En la vista Blade, el formulario usa @csrf y method="POST"; el envío provoca una recarga completa.
Enfoque con Inertia
Controlador (store):
public function store(Request $request)
{
$request->validate(['tarea' => 'required|string|max:255']);
session(['tarea' => $request->tarea]);
return redirect()->route('tarea.index');
}Componente Vue (Tarea.vue):
<form @submit.prevent="guardarTarea">
<input type="text" v-model="form.tarea" />
<button type="submit">Guardar</button>
</form>
<script setup>
import { useForm } from '@inertiajs/vue3';
const form = useForm({ tarea: '' });
function guardarTarea() {
form.post('/tarea', {
preserveState: true,
onSuccess: () => { form.tarea = ''; }
});
}
</script>Diferencias clave en el guardado:
No usamos
@csrfmanualmente: Inertia incluye automáticamente el token CSRF en las peticiones.En lugar de un envío de formulario HTML tradicional, usamos
form.post()(oform.put,form.delete, etc.) que es un método de Inertia que envía una petición POST mediantefetch(AJAX).No hay recarga de página: Inertia envía la petición, el servidor responde con una redirección (302) y Inertia sigue esa redirección (hace una petición GET al nuevo destino) y actualiza la página con la nueva respuesta. Todo esto ocurre sin recargar el navegador.
Manejo de estado:
preserveState: truemantiene el valor del input después del envío (útil para que no se borre inmediatamente). En elonSuccesslo limpiamos manualmente.Validación: Si la validación falla, Inertia devuelve automáticamente los errores en
form.errors, y puedes mostrarlos en el componente.
Conclusión: En el enfoque tradicional, el guardado implica un viaje completo (POST → redirección → GET → renderizado completo). En Inertia, es una petición AJAX que actualiza la vista sin recarga, pero el controlador sigue siendo el mismo (validación, persistencia, redirección). La redirección es clave porque Inertia la interpreta como una nueva visita a esa URL.
4. Explicación detallada del flujo en Inertia
Ciclo completo con Inertia
El usuario entra a
/tarea(GET).El controlador
index()obtiene la tarea de la sesión y llama aInertia::render('Tarea', ['tarea' => $tarea]).Inertia genera una respuesta con un JSON especial que incluye el nombre del componente y las props.
El cliente (Vue) recibe ese JSON y renderiza el componente
Tarea.vuecon las props.
El usuario escribe y envía el formulario.
Se ejecuta
guardarTarea()que llama aform.post('/tarea', ...).Inertia realiza una petición POST a
/tarea(con los datos del formulario).El controlador
store()valida, guarda en sesión y retornaredirect()->route('tarea.index').
Inertia maneja la redirección.
Inertia detecta que la respuesta es una redirección (código 302).
Automáticamente, Inertia hace una petición GET a la URL de la redirección (
/tarea) para obtener la nueva página.El controlador
index()se ejecuta de nuevo, obtiene la tarea actualizada y devuelve el componente con las nuevas props.Inertia actualiza el componente en el DOM sin recargar la página.
¿Qué pasa con el estado del formulario?
useFormcrea un objeto reactivo con los campos del formulario y además mantiene estado de envío (processing), errores (errors), etc.Al hacer
form.post, el formulario se envía y se pone en estado de "procesando" (form.processingestrue).Cuando la petición se completa, se restaura el estado. Si hay errores de validación,
form.errorsse llena y puedes mostrarlos.preserveState: trueevita que el input se reinicie a su valor inicial después del envío (útil para mostrar el valor enviado). En el ejemplo, lo limpiamos enonSuccess.
5. Comparativa detallada: Tradicional vs Inertia
| Aspecto | Tradicional (Blade) | Inertia (Vue) |
|---|---|---|
| Renderizado | Servidor: genera HTML completo. | Servidor: envía datos JSON + nombre del componente. Cliente: renderiza el componente. |
| Navegación | Cada enlace o redirección recarga la página. | Inertia intercepta los enlaces y redirecciones, hace peticiones AJAX y actualiza solo el contenido. |
| Envío de formularios | Envío tradicional (sincrónico) con recarga. | Envío asíncrono (fetch) sin recarga. |
| CSRF | Se requiere @csrf en el formulario. | Inertia lo maneja automáticamente. |
| Validación | Los errores se pasan a la vista con withErrors() o session('errors'). | Los errores se asignan a form.errors y se pueden mostrar reactivamente. |
| Redirecciones | Redirección HTTP que fuerza una nueva carga de página. | Inertia sigue la redirección y actualiza la página sin recarga. |
| Manejo de estado | Se usa old() para mantener valores después de errores. | useForm mantiene el estado del formulario de manera reactiva. |
| Interactividad | Se necesita JavaScript adicional (AJAX) para interactividad sin recarga. | La interactividad es nativa gracias a Vue y la reactividad. |
| Complejidad inicial | Menos curva de aprendizaje (Blade es simple). | Curva de aprendizaje mayor (Vue + Inertia). |
| Mantenibilidad | Puede volverse complejo con muchas interacciones (jQuery, etc.). | Más estructurado y mantenible para SPAs. |
6. Ventajas de Inertia para obtener y guardar datos
Sin API: No necesitas crear endpoints REST. Usas los mismos controladores para renderizar y procesar.
Reutilización de lógica: La validación y la persistencia son las mismas que en Laravel tradicional.
Mejor experiencia de usuario: Navegación sin recargas, transiciones suaves.
Estado compartido: Las props se pasan del servidor al cliente de manera sencilla, sin tener que hacer llamadas AJAX adicionales.
Manejo de errores integrado: Los errores de validación se manejan automáticamente.
7. Profundizando en el ejemplo
¿Por qué usamos sesión en lugar de base de datos?
Para mantener el ejemplo mínimo y funcional. En una aplicación real, en lugar de session(['tarea' => ...]), usarías un modelo Eloquent:
$tarea = new Tarea();
$tarea->descripcion = $request->tarea;
$tarea->save();Y en el index():
$tareas = Tarea::all(); // o alguna consulta
return Inertia::render('Tarea', ['tareas' => $tareas]);El flujo sería el mismo, solo cambia la persistencia.
Mostrar errores de validación
En el componente Vue, puedes añadir:
<div v-if="form.errors.tarea" style="color: red;">
{{ form.errors.tarea }}
</div>Navegación con Inertia
En lugar de <a href="/otra">, usas <Link href="/otra"> (importado de @inertia/vue3) para que la navegación sea manejada por Inertia sin recarga.
8. Conclusión
Inertia.js ofrece un enfoque moderno para construir aplicaciones web con Laravel y Vue, manteniendo la simplicidad del backend de Laravel y añadiendo la reactividad de Vue. La obtención de datos se hace mediante props que el controlador pasa al componente, y el guardado se realiza con peticiones asíncronas que no recargan la página, pero que siguen el flujo tradicional de redirección y validación.
Comparado con el enfoque clásico de Blade, Inertia reduce la cantidad de JavaScript necesario para lograr una SPA, elimina la necesidad de construir una API y ofrece una experiencia de desarrollo más cohesionada.
9. Recursos adicionales
Documentación oficial de Inertia
Documentación de Laravel con Inertia
Repositorio del ejemplo mínimo
Espero que este tutorial te haya aclarado cómo obtener y guardar datos con Inertia en Laravel, y cómo se diferencia del enfoque tradicional. ¡Anímate a probarlo!
Comentarios
Publicar un comentario