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

Bervetuna's avatar

Preventing re-render

I loop through a large amount of 'gebruikers' (that's Dutch, in this case it means users of a service, clients) and inside each loop I loop through expenses that where made for specific 'gebruikers'.

The intension is to make an invoice for every 'gebruiker'. The code for that is written and works fine.

There is a checkbox for each 'gebruiker' to include or exclude him in the process of invoicing. There is also a checkbox for every expense to include or exclude it.

To avoid re-rendering when a gebruiker's checkbox gets (un)checked, or when a expense from the database gets (un)checked, I use the wire.defer method.

@foreach ($gebruikers as $gebruiker)

	<div class="font-bold">
                  <input type="checkbox" wire:model.defer="selectedGebruikers.{{ $gebruiker->id }}"  class="form-	   checkbox">
                  <span>{{ $gebruiker->first }} {{ $gebruiker->last }}</span>
              </div>

 @foreach ($gebruiker->onkosten as $onkost)

 <div class="flex items-center space-x-2"><input 
                  
                    type="checkbox" wire:model.defer="selectedLines.{{ $gebruiker->id }}-onkost-{{ $onkost->id }}" 
                    class="form-checkbox" class="mr-2">
                    <span class="ml-2">     ONKOST #{{$onkost->id}}. 
                  {{ \Carbon\Carbon::parse($onkost->datum)->format('d/m/Y') }}: {{ $onkost->omschrijving }}. 
                 
                  €{{ round($onkost->bedrag 
                  / $onkost->gebruikers->count(),2)
                  }}
                </span>
                
                  </div>

@endforeach

@if(isset($selectedExtraLines[$gebruiker->id]))
            
              @foreach($selectedExtraLines[$gebruiker->id] as $key => $extraLine)
                  <div class="pl-2" wire:key="extra-line-{{ $gebruiker->id }}-{{ $key }}">
                      <input type="checkbox" 
                        wire:model="selectedExtraLines.{{ $gebruiker->id }}.{{ $key }}.checked" class="form-checkbox mx-2">
                      <input type="text" class="border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" placeholder="omschrijving" wire:model.lazy="selectedExtraLines.{{ $gebruiker->id }}.{{ $key }}.omschrijving">
                      <input type="text" placeholder="bedrag" class="border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" wire:mode.lazyl="selectedExtraLines.{{ $gebruiker->id }}.{{ $key }}.bedrag">
                  </div>
              @endforeach
      
          @endif

              <!-- Knop voor het toevoegen van een nieuwe lege lijn -->
              <div class="flex justify-start"><button class="bg-pink-300 hover:bg-pink-400 p-4 text-white rounded-md" wire:click="addLine({{ $gebruiker->id }})"><i class="fa-solid fa-plus"></i></button></div>


@endforeach

There is a button to add an add an ad hoc line, to include an expense that doesn't come from the database. The function addLine that is triggered when the button is clicked adds 2 input fields dynamically.

public function addLine($gebruikerId)
    {
       
        $this->selectedExtraLines[$gebruikerId][] = ['omschrijving' => '', 'bedrag' => '', 'checked' => true];
       
    }

When the addLine function is called, the selectedExtraLines array gets updated. The problem that occurs is that is re-renders the component, which takes a lot of time (since there are a lot of 'gebruikers' an expenses to loop through).

How could I add lines dynamically without re-rendering the entire component every time?

0 likes
5 replies
LaryAI's avatar
Level 58

One solution to prevent re-rendering the entire component every time the addLine function is called is to use the Livewire "wire:key" directive. This directive tells Livewire to track the identity of each element in the loop, so that it can update only the elements that have changed.

To implement this solution, add a unique identifier to each dynamically added line using the "wire:key" directive. For example:

@foreach($selectedExtraLines[$gebruiker->id] as $key => $extraLine)
    <div class="pl-2" wire:key="extra-line-{{ $gebruiker->id }}-{{ $key }}">
        ...
    </div>
@endforeach

In the addLine function, instead of updating the entire $selectedExtraLines array, use the Livewire "push" method to add a new element to the array. For example:

public function addLine($gebruikerId)
{
    $this->selectedExtraLines[$gebruikerId]->push(['omschrijving' => '', 'bedrag' => '', 'checked' => true]);
}

This way, Livewire will only update the newly added element, instead of re-rendering the entire component.

Bervetuna's avatar

@vincent15000

Thanks, but when a new row of input fields is created dynamically (addLine method), the public property selectedExtraLines gets updated and automatically the component gets re-rendered.

1 like
Snapey's avatar

@Bervetuna cache the database queries so that you can re-render quickly

otherwise you are going yo have to split the. component

1 like

Please or to participate in this conversation.