Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

agcodex01's avatar

Livewire: Sub components disappear after updating the parent component.

I have this structure of my livewire component. Parent

<?php

namespace App\Livewire\Supplier;

use App\Http\Services\SupplierService;
use App\Models\Supplier;
use Livewire\Attributes\Computed;
use Livewire\Component;
use Livewire\WithPagination;

class SupplierList extends Component
{
    use WithPagination;

    private $supplierService;

    public $isAdding = false;

    public function boot(SupplierService $supplierService)
    {
        $this->supplierService = $supplierService;
    }

    public function render()
    {
        return view('livewire.supplier.supplier-list', [
            'suppliers' => $this->supplierService->findAll()
        ]);
    }

    public function onAdd()
    {
        $this->isAdding = true;
    }

    public function delete(Supplier $supplier)
    {
        $supplier->delete();
    }
}

<div class="container-fluid pt-5 pb-3 mb-5 bg-white">
    <div class="d-flex justify-content-between mb-3">
        <button type="button" wire:click="onAdd" class="btn btn-outline-primary">Add supplier +</button>
    </div>
    <table class="table border">
        <thead>
            <tr>
                <th scope="col">Company</th>
                <th scope="col">POC</th>
                <th scope="col">Email</th>
                <th scope="col">Contact </th>
                <th scope="col">Address</th>
                <th scope="col">Action</th>
            </tr>
        </thead>
        <tbody>
            @if ($isAdding)
                <livewire:supplier.supplier-detail :key="'upsert:key'" :upserting="$isAdding" />
            @endif
            @foreach ($suppliers as $supplier)
                <livewire:supplier.supplier-detail :key="'list-key-' . $supplier->id" :$supplier />
            @endforeach
        </tbody>
    </table>
    <div class="d-flex justify-content-between align-items-center">
        Showing {{ $suppliers->firstItem() }} to {{ $suppliers->lastItem() }} of total
        {{ $suppliers->total() }} entries
        {{ $suppliers->appends(request()->query())->onEachSide(1)->links('pagination::bootstrap-4') }}
    </div>
</div>

Sub component

<?php

namespace App\Livewire\Supplier;

use App\Livewire\Forms\Supplier\SupplierForm;
use App\Models\Supplier;
use Livewire\Component;

class SupplierDetail extends Component
{
    public SupplierForm $form;

    public bool $upserting;

    public function mount(?Supplier $supplier = null)
    {
        if ($supplier == null) {
            $supplier = new Supplier();
        }

        $this->form->setSupplier($supplier);
    }

    public function render()
    {
        return view('livewire.supplier.supplier-detail');
    }

    public function onSave()
    {
        $this->form->store();
    }

    public function onEdit() {
        $this->upserting = true;
    }
}

Livewire Form

<?php

namespace App\Livewire\Forms\Supplier;

use App\Models\Supplier;
use Livewire\Attributes\Validate;
use Livewire\Form;

class SupplierForm extends Form
{
    public ?Supplier $supplier;

    #[Validate('required|min:3|max:50')]
    public string $company = '';

    #[Validate('required|min:2|max:20')]
    public string $poc = '';

    #[Validate('sometimes|min:2|max:30|email:rfc,dns')]
    public string $poc_email = '';

    #[Validate('required|min:6|max:20')]
    public string $contact = '';

    #[Validate('required|min:6|max:100')]
    public string $address = '';

    public function setSupplier(Supplier $supplier)
    {
        $this->supplier = $supplier;

        $this->company = $supplier->company ?? '';
        $this->poc = $supplier->poc ?? '';
        $this->poc_email = $supplier->poc_email ?? '';
        $this->contact = $supplier->contact ?? '';
        $this->address = $supplier->address ?? '';
    }

    public function store() {
        $this->validate();

        return Supplier::create($this->all());
    }
}
<tr>
    <td>
        @if ($upserting)
            <input type="text" class="form-control" wire:model="form.company">
        @else
            {{ $form->company }}
        @endif
    </td>
    <td>
        @if ($upserting)
            <input type="text" class="form-control" wire:model="form.poc">
        @else
            {{ $form->poc }}
        @endif

    </td>
    <td>
        @if ($upserting)
            <input type="email" class="form-control" wire:model="form.poc_email">
        @else
            {{ $form->poc_email }}
        @endif
    </td>
    <td>
        @if ($upserting)
            <input type="text" class="form-control" wire:model="form.contact">
        @else
            {{ $form->contact }}
        @endif

    </td>
    <td>
        @if ($upserting)
            <input type="text" class="form-control" wire:model="form.address">
        @else
            {{ $form->address }}
        @endif

    </td>
    <td>
        @if ($upserting)
            <button type="button" wire:click="onSave" class="btn"><i class="fa text-primary fa-save"></i></button>
        @else
            <button type="button" wire:click="onEdit" class="btn"><i class="fa text-info fa-edit"></i></button>
        @endif

        @if ($form)
            <button wire:click="$parent.delete({{ $form->supplier }})" class="btn"><i
                    class="fa text-danger fa-trash"></i></button>
        @endif

    </td>
</tr>

Now my issue here. whenever I click the Add supplier button in the parent. What only show is

@if ($isAdding)
     <livewire:supplier.supplier-detail :key="'upsert:key'" :upserting="$isAdding" />
 @endif

and the missing part is this

@foreach ($suppliers as $supplier)
   <livewire:supplier.supplier-detail :key="'list-key-' . $supplier->id" :$supplier />
@endforeach

Did I missing something? or this is a bug from livewire?

Livewire version: v3.4.7

0 likes
1 reply
DivDax's avatar

Hey @agcodex01, i have the exact same problem. Before pulling out my hair, did you find a solution for this issue?

I checked:

  • wire:key / :key on all components
  • every component has a single root element (no comments before or after root element)

Please or to participate in this conversation.