CRUD completo con Livewire 4 y Laravel 12 en un solo archivo (Single-File Component)

Autor: J. Luis, 29 enero, 2026

Tutorial paso a paso para crear un CRUD con Livewire 4 en Laravel 12 usando Single-File Components: lista de posts, crear, editar, eliminar, validación reactiva y mensaje

CRUD completo con Livewire 4 y Laravel 12 en un solo archivo (Single-File Component)

Hoy vamos a crear un CRUD básico pero funcional de posts (título + contenido) usando Livewire 4 junto con Laravel 12, aprovechando una de las características más potentes de Livewire 4: los Single-File Components (todo el componente en un solo archivo PHP + su vista Blade asociada).

¿Qué vamos a lograr en este tutorial?

  • Mostrar una lista de posts con paginación manual (carga todos los últimos primero)
  • Crear un post nuevo
  • Editar un post existente
  • Eliminar un post con confirmación
  • Validación en tiempo real con wire:model.live
  • Mensajes de éxito con session()->flash
  • Cambiar entre modos (lista / crear / editar) sin recargar la página
  • Todo en un solo componente Livewire, sin necesidad de controladores ni rutas extras

Ventajas que vamos a aprovechar de Livewire 4:

  • Lógica y vista muy cercanas (menos saltos entre archivos)
  • Validación automática y reactiva
  • Comunicación bidireccional con el servidor sin escribir JavaScript
  • Simplicidad extrema para aplicaciones internas, paneles de administración o prototipos rápidos

Requisitos previos

  • Laravel 12 instalado
  • Livewire 4 instalado (composer require livewire/livewire)
  • Modelo Post con migración (title string, content text)

Paso 1: Crear el componente

Ejecuta:

php artisan make:livewire posts

Esto crea:

  • app/Livewire/Posts.php
  • resources/views/livewire/posts.blade.php

Paso 2: Código completo del componente (Posts.php) PHP

<?php

namespace App\Livewire;

use Livewire\Component;
use App\Models\Post;

class Posts extends Component
{
    public string $mode = "list"; // list - create - edit

    public $posts;
    public $postId = null;
    public $title = "";
    public $content = "";

    // ────────────────────────────────────────────────
    // FUNCIONES EXPLICADAS
    // ────────────────────────────────────────────────

    /**
     * Se ejecuta al montar el componente (primera carga)
     */
    public function mount()
    {
        $this->loadPosts();
    }

    /**
     * Carga TODOS los posts desde la base de datos
     * (se usa cada vez que necesitamos refrescar la lista)
     */
    public function loadPosts()
    {
        $this->posts = Post::latest()->get();
    }

    /**
     * Prepara el formulario para CREAR un post nuevo
     * Limpia los campos y cambia el modo a "create"
     */
    public function showCreate()
    {
        $this->resetForm();
        $this->mode = "create";
    }

    /**
     * Carga los datos de un post existente para editarlo
     * @param int $id ID del post a editar
     */
    public function showEdit($id)
    {
        $post = Post::findOrFail($id);
        $this->postId = $post->id;
        $this->title = $post->title;
        $this->content = $post->content;
        $this->mode = "edit";
    }

    /**
     * Guarda o actualiza el post (función principal del CRUD)
     * - Valida los datos
     * - Si hay $postId → actualiza
     * - Si no hay → crea nuevo
     */
    public function save()
    {
        $this->validate();

        if ($this->postId) {
            // Actualizar post existente
            Post::find($this->postId)->update([
                'title'   => $this->title,
                'content' => $this->content
            ]);
            session()->flash('status', 'Post actualizado correctamente');
        } else {
            // Crear post nuevo
            Post::create([
                'title'   => $this->title,
                'content' => $this->content,
            ]);
            session()->flash('status', 'Post creado correctamente');
        }

        $this->resetForm();
        $this->mode = "list";
        $this->loadPosts();
    }

    /**
     * Elimina un post de la base de datos
     * @param int $id ID del post a eliminar
     */
    public function delete($id)
    {
        $post = Post::findOrFail($id)->delete();
        session()->flash('status', 'Post eliminado correctamente');
        $this->loadPosts();
    }

    /**
     * Define las reglas de validación (Livewire las usa automáticamente)
     */
    public function rules(): array
    {
        return [
            'title'   => ['required', 'string', 'min:3', 'max:100'],
            'content' => ['required', 'string', 'min:10'],
        ];
    }

    /**
     * Limpia el formulario y quita los errores de validación
     * (muy útil para reutilizar entre crear y editar)
     */
    private function resetForm()
    {
        $this->reset(['postId', 'title', 'content']);
        $this->resetValidation();
    }

    public function render()
    {
        return view('livewire.posts');
    }
}

Paso 3: La vista (posts.blade.php) – sin cambios blade

<div>
    @if (session('status'))
        <div>{{session('status')}}</div>        
    @endif

    @if ($mode==="list")
        <h1>Mis Posts</h1>
        <button wire:click="showCreate">+ Nuevo post</button>
        <!-- LIST-->
        <table>
            <thead>
                <tr>
                    <th>Título</th>
                    <th>Contenido</th>
                    <th>Acciones</th>
                </tr>
            </thead>
            <tbody>
                @forelse($posts as $post)
                <tr>
                        <td>{{ $post->title }}</td>
                        <td>{{ Str::limit($post->content, 90) }}</td>
                        <td>
                            <button wire:click="showEdit({{ $post->id }})">Editar</button>
                            <button wire:click="delete({{ $post->id }})" onclick="return confirm('¿Seguro que quieres eliminar este post?')">Eliminar</button>
                        </td>
                </tr>
                @empty
                    <tr>
                        <td colspan="3">No hay posts aún. Crea uno con el botón de arriba.</td>
                    </tr>
                @endforelse
            </tbody>
        </table>
        
    @elseif($mode==="create" || $mode==="edit")
        <!-- FORM -->
        <h1>{{ $mode === 'create' ? 'Crear Nuevo Post' : 'Editar Post' }}</h1>
        <form wire:submit="save">
            <div>
                <label>Título</label>
                <input wire:model.live="title" type="text">
                @error('title') <div>{{ $message }}</div> @enderror
            </div>
            <div>
                <label>Contenido</label>
                <textarea wire:model.live="content" rows="1"></textarea>
                @error('content') <div>{{ $message }}</div> @enderror
            </div>
            <div>
                <button type="submit">{{ $mode === 'create' ? 'Guardar Post' : 'Actualizar Post' }}</button>
                <button type="button" wire:click="cancel">Cancelar</button>
            </div>
        </form>

    @endif
</div>

Resumen de lo que hace cada parte principal

  • mount() → carga inicial de posts
  • loadPosts() → refresca la lista siempre que cambie algo
  • showCreate() → limpia y abre formulario nuevo
  • showEdit($id) → carga datos del post y abre modo edición
  • save() → crea o actualiza + mensaje + vuelve a lista
  • delete($id) → elimina + mensaje + refresca
  • rules() → validaciones automáticas de Livewire
  • resetForm() → limpia campos y errores
  • cancel() → regresa a lista sin guardar

¿Cómo usarlo?

  1. Agrega la ruta en web.php:

PHP

// livewire - crud posts

Route::livewire('/posts','post-crud');
  1. Visita /posts
  2. ¡Listo! Tienes un CRUD reactivo sin escribir JavaScript ni controladores.

¿Qué te parece? ¿Quieres que en la siguiente parte agreguemos búsqueda en vivo, paginación real con WithPagination, o subida de imágenes?

¡Cuéntame en los comentarios! 🚀

#Laravel #Livewire #Livewire4 #Laravel12 #PHP




Leido 35 veces | 0 usuarios

Descarga del código fuente

CRUD completo con Livewire 4 y Laravel 12 en un solo archivo (Single-File Component)

Accede al código fuente esencial de nuestra aplicación en formato ZIP ó TXT. Ideal para desarrolladores que desean personalizar o integrar nuestra solución.

  • [ Pago: Paypal ]
  • [ Precio: USD 5.00 ]
  • [ Descargas: 0 ]

Compartir link del tutorial con tus amigos

CÓDIGO FUENTE: USD 5.00

Conversar con J.Luis

Codea Applications

México, Colombia, España, Venezuela, Argentina, Bolivia, Perú