3-CRUD de Tareas en Laravel con Explicación de Componentes Blade

  Componentes de Blade en Laravel, que se crean con el comando php artisan make:component. Estos componentes sirven para crear elementos reutilizables en tus vistas (como botones, cards, formularios, etc.). Vamos a explicarlos de forma clara:


🔹 Tipos de Componentes en Laravel

Hay dos tipos principales de componentes Blade:

  1. Componentes Anónimos (simples, sin clase asociada).

  2. Componentes de Clase (tienen una clase PHP para lógica adicional).


1. Componentes Anónimos (Archivos simples)

  • Son ideales para componentes sencillos (ej: alertas, badges).

  • Se crean manualmente en resources/views/components.

Ejemplo:

Paso 1: Crea un archivo Blade (ej: alert.blade.php):

php
<!-- resources/views/components/alert.blade.php -->
<div class="alert alert-{{ $type }}">
    {{ $slot }} <!-- Contenido que se pasa al componente -->
</div>

Paso 2: Usalo en cualquier vista:

php
<x-alert type="success">
    ¡Éxito! Tu acción se completó.
</x-alert>

2. Componentes de Clase (Con lógica PHP)

  • Tienen una clase asociada para manejar datos o lógica compleja.

  • Se crean con Artisan:

Ejemplo: Crear un componente "Card"

Paso 1: Genera el componente:

bash
php artisan make:component Card

Esto crea dos archivos:

  • app/View/Components/Card.php (clase del componente).

  • resources/views/components/card.blade.php (vista).

Paso 2: Define propiedades en la clase:

php
// app/View/Components/Card.php
class Card extends Component {
    public $title;
    public $description;

    public function __construct($title, $description) {
        $this->title = $title;
        $this->description = $description;
    }

    public function render() {
        return view('components.card');
    }
}

Paso 3: Diseña la vista (card.blade.php):

php
<div class="card">
    <h2>{{ $title }}</h2>
    <p>{{ $description }}</p>
    {{ $slot }} <!-- Contenido dinámico -->
</div>

Paso 4: Úsalo en una vista:

php
<x-card title="Laravel" description="Framework PHP">
    <button>Ver más</button>
</x-card>

🔥 Ventajas de Usar Componentes

  • Reutilización: Evitas repetir código HTML/PHP.

  • Organización: Separas la lógica (clase) de la presentación (vista).

  • Props: Puedes pasar datos dinámicos (titledescription, etc.).

  • Slots: Permites contenido personalizado dentro del componente.


📌 Ejemplo Práctico: Botón Reutilizable

bash
php artisan make:component Button

Clase (Button.php):

php
public $color;

public function __construct($color = 'blue') {
    $this->color = $color;
}

Vista (button.blade.php):

php
<button class="bg-{{ $color }}-500 text-white p-2 rounded">
    {{ $slot }}
</button>

Uso:

php
<x-button color="red">Eliminar</x-button>
<x-button>Guardar</x-button> <!-- Color por defecto: blue -->

🎯 Conclusión

  • php artisan make:component crea componentes con clase + vista.

  • Los anónimos son para piezas simples (solo vista).

  • Usa props para datos y slots para contenido flexible.

CRUD de Tareas en Laravel con Explicación de Componentes Blade

Voy a recrear el CRUD explicando detalladamente cada componente Blade y su función. Este enfoque te ayudará a entender mejor cómo estructurar tus vistas en Laravel.

Estructura Base Blade

1. Layout Principal (resources/views/layouts/app.blade.php)

php
<!DOCTYPE html>
<html lang="es">
<head>
    <!-- @yield define un área que puede ser rellenada por las vistas hijas -->
    <title>@yield('title', 'Gestor de Tareas')</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- @stack crea una pila para acumular contenido (usado para CSS/JS específicos) -->
    @stack('styles')
</head>
<body>
    <!-- Cabecera común a todas las páginas -->
    <header class="bg-primary text-white py-3">
        <div class="container">
            <div class="d-flex justify-content-between align-items-center">
                <!-- Las vistas pueden sobrescribir el header -->
                <h1>@yield('header')</h1>
                <!-- Área para acciones específicas del header -->
                @yield('header-actions')
            </div>
        </div>
    </header>

    <!-- Contenido principal (obligatorio en todas las vistas) -->
    <main class="container py-4">
        @yield('content')
    </main>

    <!-- Footer común -->
    <footer class="bg-light py-3 mt-4">
        <div class="container text-center">
            <p class="mb-0">Sistema de Tareas &copy; {{ date('Y') }}</p>
        </div>
    </footer>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <!-- Pila para scripts específicos de vistas -->
    @stack('scripts')
</body>
</html>

Componentes Blade Explicados

2. Vista Index (resources/views/tasks/index.blade.php)

php
<!-- @extends indica qué layout usar como base -->
@extends('layouts.app')

<!-- @section rellena el yield 'title' en el layout -->
@section('title', 'Listado de Tareas')

<!-- @section rellena el yield 'header' -->
@section('header', 'Todas las Tareas')

<!-- @section rellena el yield 'header-actions' -->
@section('header-actions')
    <!-- Botón para crear nueva tarea -->
    <a href="{{ route('tasks.create') }}" class="btn btn-light">
        <i class="bi bi-plus-circle"></i> Nueva Tarea
    </a>
@endsection

<!-- @section rellena el yield 'content' (parte principal) -->
@section('content')
    <!-- @include incluye una sub-vista (partial) -->
    @include('partials.alerts')

    <!-- Tarjeta contenedora -->
    <div class="card shadow-sm">
        <div class="card-body">
            <!-- @forelse es un loop con caso vacío incorporado -->
            @forelse($tasks as $task)
                <!-- Componente de tarea individual -->
                <div class="task-item py-2 border-bottom">
                    <!-- @each podría usarse aquí para iterar un componente -->
                    <div class="d-flex justify-content-between align-items-center">
                        <span>{{ $task->name }}</span>
                        <div class="actions">
                            <!-- Formulario de edición (usando @method('PUT')) -->
                            <a href="{{ route('tasks.edit', $task->id) }}" class="btn btn-sm btn-outline-primary">
                                Editar
                            </a>
                            
                            <!-- Formulario de eliminación -->
                            <form action="{{ route('tasks.destroy', $task->id) }}" method="POST" class="d-inline">
                                @csrf
                                @method('DELETE')
                                <button type="submit" class="btn btn-sm btn-outline-danger" 
                                    onclick="return confirm('¿Eliminar esta tarea?')">
                                    Eliminar
                                </button>
                            </form>
                        </div>
                    </div>
                </div>
            @empty
                <!-- Caso cuando no hay tareas -->
                <div class="text-center py-5">
                    <h4 class="text-muted">No hay tareas registradas</h4>
                    <a href="{{ route('tasks.create') }}" class="btn btn-primary mt-3">
                        Crear Primera Tarea
                    </a>
                </div>
            @endforelse

            <!-- Paginación (si está habilitada) -->
            @if($tasks->hasPages())
                <div class="mt-4">
                    {{ $tasks->links() }}
                </div>
            @endif
        </div>
    </div>
@endsection

<!-- @push añade contenido a la pila 'scripts' -->
@push('scripts')
<script>
    // Scripts específicos para esta vista
    console.log('Página de listado cargada');
</script>
@endpush

3. Partial de Alertas (resources/views/partials/alerts.blade.php)

php
<!-- Componente reutilizable para mostrar mensajes flash -->
@if(session('success'))
    <div class="alert alert-success alert-dismissible fade show mb-4">
        {{ session('success') }}
        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
    </div>
@endif

@if($errors->any())
    <div class="alert alert-danger alert-dismissible fade show mb-4">
        <ul class="mb-0">
            <!-- @foreach para iterar errores -->
            @foreach($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
    </div>
@endif

4. Vista de Formulario (resources/views/tasks/form.blade.php)

php
<!-- Componente de formulario reutilizable -->
<div class="card shadow-sm">
    <div class="card-header">
        <h5 class="card-title mb-0">
            <!-- $slot permite contenido dinámico -->
            {{ $slot }}
        </h5>
    </div>
    <div class="card-body">
        <form action="{{ $action }}" method="POST">
            @csrf
            <!-- @isset comprueba si la variable está definida -->
            @isset($method)
                @method($method)
            @endisset

            <div class="mb-3">
                <label for="name" class="form-label">Nombre de la Tarea</label>
                <input type="text" class="form-control @error('name') is-invalid @enderror" 
                       id="name" name="name" value="{{ old('name', $task->name ?? '') }}" required>
                <!-- @error muestra errores de validación -->
                @error('name')
                    <div class="invalid-feedback">{{ $message }}</div>
                @enderror
            </div>

            <div class="d-flex justify-content-end gap-2">
                <a href="{{ route('tasks.index') }}" class="btn btn-secondary">
                    Cancelar
                </a>
                <button type="submit" class="btn btn-primary">
                    {{ $submitText ?? 'Guardar' }}
                </button>
            </div>
        </form>
    </div>
</div>

5. Vista Create (resources/views/tasks/create.blade.php)

php
@extends('layouts.app')

@section('title', 'Crear Nueva Tarea')

@section('header', 'Nueva Tarea')

@section('content')
    <!-- @component es una alternativa para incluir componentes -->
    @component('tasks.form', [
        'action' => route('tasks.store'),
        'task' => new App\Models\Task(), // Objeto vacío para evitar errores
        'submitText' => 'Crear Tarea'
    ])
        Crear Nueva Tarea
    @endcomponent
@endsection

6. Vista Edit (resources/views/tasks/edit.blade.php)

php
@extends('layouts.app')

@section('title', 'Editar Tarea')

@section('header', 'Editar Tarea')

@section('content')
    <!-- Uso del componente form con parámetros -->
    @include('tasks.form', [
        'action' => route('tasks.update', $task->id),
        'method' => 'PUT',
        'task' => $task,
        'submitText' => 'Actualizar'
    ])
@endsection

Explicación de Componentes Clave

  1. Herencia (@extends):

    • Establece la plantilla base que se utilizará

    • Todas las vistas "extienden" del layout principal

  2. Secciones (@section/@yield):

    • @section define contenido para áreas específicas

    • @yield muestra el contenido de esas secciones en el layout

  3. Pilas (@stack/@push):

    • Permiten agregar CSS/JS específicos para cada vista

    • El contenido se acumula y se renderiza donde está @stack

  4. Condicionales (@if, @unless, @isset):

    • Control de flujo para mostrar/ocultar elementos

    • Ejemplo: mostrar errores solo cuando existen

  5. Bucles (@foreach, @for, @while):

    • Para iterar sobre colecciones de datos

    • @forelse incluye caso vacío incorporado

  6. Componentes (@component/@slot):

    • Crea bloques reutilizables con parámetros

    • Alternativa a @include con más flexibilidad

  7. Includes (@include):

    • Para dividir vistas en partes reutilizables

    • Ejemplo: formulario compartido entre create/edit

  8. Directivas de Formulario:

    • @csrf: Agrega token de seguridad

    • @method: Para métodos HTTP como PUT/DELETE

    • @error: Manejo de errores de validación

Ventajas de esta Estructura

  1. DRY (Don't Repeat Yourself):

    • El formulario se escribe una vez y se reutiliza

    • El layout base evita repetir código HTML

  2. Organización Clara:

    • Cada componente tiene una responsabilidad única

    • Fácil de mantener y escalar

  3. Flexibilidad:

    • Las vistas pueden sobrescribir solo lo necesario

    • Componentes aceptan parámetros dinámicos

  4. Legibilidad:

    • El código es más fácil de entender

    • Separación clara entre estructura y contenido

Esta estructura es escalable y puedes agregar fácilmente:

  • Más componentes específicos

  • Secciones adicionales en el layout

  • Estilos/scripts específicos por vista

  • Más partials para elementos reutilizables


RUD de Tareas con Componentes de Clase en Laravel

Ahora voy a recrear el CRUD utilizando componentes de clase como php artisan make:component NoteCard. Este enfoque es más moderno y organizado, permitiendo una mejor separación de responsabilidades.

1. Crear los Componentes

Primero, generamos los componentes necesarios:

bash
php artisan make:component TaskCard
php artisan make:component TaskForm
php artisan make:component Alert

2. Componente Alert (app/View/Components/Alert.php)

php
<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Alert extends Component
{
    public $type;
    public $message;
    public $dismissible;

    public function __construct($type = 'success', $message = null, $dismissible = true)
    {
        $this->type = $type;
        $this->message = $message ?? session('success');
        $this->dismissible = $dismissible;
    }

    public function render()
    {
        return view('components.alert');
    }
}

resources/views/components/alert.blade.php:

php
@if($message)
<div class="alert alert-{{ $type }} @if($dismissible) alert-dismissible fade show @endif mb-4">
    {{ $message }}
    @if($dismissible)
    <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
    @endif
</div>
@endif

3. Componente TaskCard (app/View/Components/TaskCard.php)

php
<?php

namespace App\View\Components;

use Illuminate\View\Component;

class TaskCard extends Component
{
    public $task;
    public $showActions;

    public function __construct($task, $showActions = true)
    {
        $this->task = $task;
        $this->showActions = $showActions;
    }

    public function render()
    {
        return view('components.task-card');
    }
}

resources/views/components/task-card.blade.php:

php
<div class="task-card card shadow-sm mb-3">
    <div class="card-body">
        <div class="d-flex justify-content-between align-items-center">
            <span class="task-name">{{ $task->name }}</span>
            
            @if($showActions)
            <div class="task-actions btn-group">
                <a href="{{ route('tasks.edit', $task->id) }}" 
                   class="btn btn-sm btn-outline-primary">
                    Editar
                </a>
                
                <form action="{{ route('tasks.destroy', $task->id) }}" method="POST">
                    @csrf
                    @method('DELETE')
                    <button type="submit" class="btn btn-sm btn-outline-danger"
                            onclick="return confirm('¿Eliminar esta tarea?')">
                        Eliminar
                    </button>
                </form>
            </div>
            @endif
        </div>
    </div>
</div>

4. Componente TaskForm (app/View/Components/TaskForm.php)

php
<?php

namespace App\View\Components;

use Illuminate\View\Component;
use App\Models\Task;

class TaskForm extends Component
{
    public $task;
    public $action;
    public $method;
    public $submitText;

    public function __construct($task = null, $action = null, $method = 'POST', $submitText = 'Guardar')
    {
        $this->task = $task ?? new Task();
        $this->action = $action ?? ($task ? route('tasks.update', $task->id) : route('tasks.store'));
        $this->method = $method;
        $this->submitText = $submitText;
    }

    public function render()
    {
        return view('components.task-form');
    }
}

resources/views/components/task-form.blade.php:

php
<div class="task-form card shadow-sm">
    <div class="card-body">
        <form action="{{ $action }}" method="POST">
            @csrf
            @method($method)

            <div class="mb-3">
                <label for="name" class="form-label">Nombre de la Tarea</label>
                <input type="text" class="form-control @error('name') is-invalid @enderror" 
                       id="name" name="name" value="{{ old('name', $task->name) }}" required>
                @error('name')
                    <div class="invalid-feedback">{{ $message }}</div>
                @enderror
            </div>

            <div class="d-flex justify-content-end gap-2">
                <a href="{{ route('tasks.index') }}" class="btn btn-secondary">
                    Cancelar
                </a>
                <button type="submit" class="btn btn-primary">
                    {{ $submitText }}
                </button>
            </div>
        </form>
    </div>
</div>

5. Actualización de las Vistas

Layout Principal (resources/views/layouts/app.blade.php)

php
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title', 'Gestor de Tareas')</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    @stack('styles')
</head>
<body>
    <header class="bg-primary text-white py-3">
        <div class="container">
            <div class="d-flex justify-content-between align-items-center">
                <h1>@yield('header')</h1>
                @yield('header-actions')
            </div>
        </div>
    </header>

    <main class="container py-4">
        <x-alert />
        @yield('content')
    </main>

    <footer class="bg-light py-3 mt-4">
        <div class="container text-center">
            <p class="mb-0">Sistema de Tareas &copy; {{ date('Y') }}</p>
        </div>
    </footer>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    @stack('scripts')
</body>
</html>

Vista Index (resources/views/tasks/index.blade.php)

php
@extends('layouts.app')

@section('title', 'Listado de Tareas')
@section('header', 'Todas las Tareas')

@section('header-actions')
    <a href="{{ route('tasks.create') }}" class="btn btn-light">
        <i class="bi bi-plus-circle"></i> Nueva Tarea
    </a>
@endsection

@section('content')
    @forelse($tasks as $task)
        <x-task-card :task="$task" />
    @empty
        <div class="text-center py-5">
            <h4 class="text-muted">No hay tareas registradas</h4>
            <a href="{{ route('tasks.create') }}" class="btn btn-primary mt-3">
                Crear Primera Tarea
            </a>
        </div>
    @endforelse

    @if($tasks->hasPages())
        <div class="mt-4">
            {{ $tasks->links() }}
        </div>
    @endif
@endsection

Vista Create (resources/views/tasks/create.blade.php)

php
@extends('layouts.app')

@section('title', 'Crear Nueva Tarea')
@section('header', 'Nueva Tarea')

@section('content')
    <x-task-form submit-text="Crear Tarea" />
@endsection

Vista Edit (resources/views/tasks/edit.blade.php)

php
@extends('layouts.app')

@section('title', 'Editar Tarea')
@section('header', 'Editar Tarea')

@section('content')
    <x-task-form :task="$task" method="PUT" submit-text="Actualizar" />
@endsection

6. Ventajas de este Enfoque

  1. Mejor Organización:

    • Cada componente tiene su propia clase y vista

    • Lógica bien encapsulada

  2. Reutilización:

    • Los componentes pueden usarse en múltiples vistas

    • Fácil de mantener y actualizar

  3. Claridad:

    • Las vistas principales son más limpias y legibles

    • La lógica compleja está en las clases de componentes

  4. Flexibilidad:

    • Componentes aceptan parámetros configurables

    • Fácil de extender y personalizar

  5. Coherencia:

    • Estilos y comportamientos consistentes

    • Menos duplicación de código

Uso de los Componentes

  1. Componente Alert:

    php
    <x-alert type="success" :message="session('success')" />
  2. Componente TaskCard:

    php
    <x-task-card :task="$task" :show-actions="false" />
  3. Componente TaskForm:

    php
    <x-task-form :task="$task" method="PUT" submit-text="Actualizar" />

Este enfoque con componentes de clase es ideal para aplicaciones medianas a grandes, donde la reutilización y mantenibilidad del código son prioritarias. Cada componente se convierte en un bloque de construcción independiente que puede ser probado y desarrollado por separado


mplementación de Componentes en el CRUD de Tareas (Explicación Paso a Paso)

Basándome en el ejemplo anterior del CRUD simple de tareas, voy a explicar cómo implementar componentes de clase (php artisan make:component) para mejorar la estructura.

Explicación del Ejemplo Original (sin componentes)

El CRUD original tenía:

  1. Estructura básica:

    • Layout principal (app.blade.php)

    • Vistas para listar, crear y editar tareas

    • Un único campo "nombre" para las tareas

  2. Flujo de trabajo:

  3. Problemas del enfoque original:

    • Código duplicado en formularios

    • Poca reutilización de elementos UI

    • Mezcla de lógica y presentación

Implementación con Componentes

Paso 1: Crear el Componente TaskForm

Generamos el componente:

bash
php artisan make:component TaskForm

Esto crea dos archivos:

  1. app/View/Components/TaskForm.php (clase del componente)

  2. resources/views/components/task-form.blade.php (vista del componente)

Paso 2: Configurar el Componente TaskForm

app/View/Components/TaskForm.php:

php
<?php

namespace App\View\Components;

use Illuminate\View\Component;
use App\Models\Task;

class TaskForm extends Component
{
    public $task;
    public $action;
    public $method;
    public $submitText;

    public function __construct($task = null)
    {
        // Si no se pasa una tarea, creamos una nueva instancia
        $this->task = $task ?? new Task();
        
        // Determinar acción y método HTTP
        $this->action = $task ? route('tasks.update', $task->id) : route('tasks.store');
        $this->method = $task ? 'PUT' : 'POST';
        $this->submitText = $task ? 'Actualizar' : 'Guardar';
    }

    public function render()
    {
        return view('components.task-form');
    }
}

resources/views/components/task-form.blade.php:

php
<div class="card mt-4">
    <div class="card-body">
        <form action="{{ $action }}" method="POST">
            @csrf
            @method($method)

            <div class="mb-3">
                <label for="name" class="form-label">Nombre de la Tarea</label>
                <input type="text" class="form-control @error('name') is-invalid @enderror" 
                       id="name" name="name" value="{{ old('name', $task->name) }}" required>
                @error('name')
                    <div class="invalid-feedback">{{ $message }}</div>
                @enderror
            </div>

            <div class="d-flex justify-content-end">
                <a href="{{ route('tasks.index') }}" class="btn btn-secondary me-2">Cancelar</a>
                <button type="submit" class="btn btn-primary">{{ $submitText }}</button>
            </div>
        </form>
    </div>
</div>

Paso 3: Modificar las Vistas para Usar el Componente

Vista Create (resources/views/tasks/create.blade.php):

php
@extends('layouts.app')

@section('title', 'Crear Nueva Tarea')

@section('content')
<div class="container">
    <h1 class="my-4">Crear Nueva Tarea</h1>
    
    <!-- Usamos el componente -->
    <x-task-form />
</div>
@endsection

Vista Edit (resources/views/tasks/edit.blade.php):

php
@extends('layouts.app')

@section('title', 'Editar Tarea')

@section('content')
<div class="container">
    <h1 class="my-4">Editar Tarea</h1>
    
    <!-- Pasamos la tarea existente al componente -->
    <x-task-form :task="$task" />
</div>
@endsection

Paso 4: Crear un Componente para las Alertas

bash
php artisan make:component Alert

app/View/Components/Alert.php:

php
<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Alert extends Component
{
    public $type;
    public $message;
    
    public function __construct($type = 'success', $message = null)
    {
        $this->type = $type;
        $this->message = $message ?? session('success');
    }

    public function render()
    {
        return view('components.alert');
    }
}

resources/views/components/alert.blade.php:

php
@if($message)
<div class="alert alert-{{ $type }} alert-dismissible fade show mt-4">
    {{ $message }}
    <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif

Paso 5: Actualizar el Layout para Usar Alertas

resources/views/layouts/app.blade.php (agregar esto en el main):

php
<main class="container py-4">
    <!-- Componente de alerta -->
    <x-alert />
    
    @yield('content')
</main>

Beneficios de esta Implementación

  1. Reducción de duplicación:

    • El formulario se escribe una sola vez

    • Lógica compartida entre create/edit

  2. Mejor organización:

  3. Mantenimiento más fácil:

    • Cambios en formularios solo en un lugar

    • Comportamiento consistente

  4. Reutilización:

    • Los componentes pueden usarse en otras partes

    • Fácil de extender

Ejemplo Completo: Vista Index con Componentes

Podemos llevar esto más lejos creando un componente para las tarjetas de tareas:

bash
php artisan make:component TaskCard

app/View/Components/TaskCard.php:

php
<?php

namespace App\View\Components;

use Illuminate\View\Component;

class TaskCard extends Component
{
    public $task;
    
    public function __construct($task)
    {
        $this->task = $task;
    }

    public function render()
    {
        return view('components.task-card');
    }
}

resources/views/components/task-card.blade.php:

php
<div class="card mb-3">
    <div class="card-body d-flex justify-content-between align-items-center">
        <span>{{ $task->name }}</span>
        <div>
            <a href="{{ route('tasks.edit', $task->id) }}" class="btn btn-sm btn-warning">Editar</a>
            <form action="{{ route('tasks.destroy', $task->id) }}" method="POST" class="d-inline">
                @csrf
                @method('DELETE')
                <button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('¿Eliminar?')">Eliminar</button>
            </form>
        </div>
    </div>
</div>

Ahora la vista index quedaría:

resources/views/tasks/index.blade.php:

php
@extends('layouts.app')

@section('title', 'Lista de Tareas')

@section('content')
<div class="container">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1>Lista de Tareas</h1>
        <a href="{{ route('tasks.create') }}" class="btn btn-primary">Nueva Tarea</a>
    </div>

    @forelse($tasks as $task)
        <x-task-card :task="$task" />
    @empty
        <div class="alert alert-info">No hay tareas registradas</div>
    @endforelse
</div>
@endsection

Conclusión

La implementación con componentes:

  1. Organiza mejor el código

  2. Facilita el mantenimiento

  3. Promueve la reutilización

  4. Separa claramente la lógica de la presentación

Los componentes son especialmente útiles cuando:

  • Tienes elementos que se repiten

  • Necesitas mantener consistencia en la UI

  • Quieres encapsular lógica compleja

Comentarios

Entradas más populares de este blog

0-Sistema de Tareas

13-CRUD en Laravel para Web y API con Rutas Normales (No Resource)

10-Introducción a Blade en Laravel con un Ejemplo Práctico