Real-Time updates in Livewire 3

Imagine you're building a job board application. Users need to filter job listings by country, and immediately see the corresponding cities within that country populate in a second dropdown – no waiting, no full page reloads. If you've used Livewire 2, you might assume wire:model would handle this automatically. However, Livewire 3 introduced a key change that can trip you up if you're not aware of it.

This article clarifies the new wire:model.live modifier in Livewire 3, focusing on the crucial scenario of dependent dropdowns. I'll demonstrate this using an example of a country/city selection. Hopefully, you will learn how to build more responsive and user-friendly web applications. I'll also touch on how you can make fewer network requests in your Livewire-powered applications.

Understanding Livewire 3's Deferred Updates

The biggest shift in Livewire 3 is that wire:model is now deferred by default. This means changes to input fields aren't instantly synced with your Livewire component. Livewire waits for an action (like clicking a "Submit" button) to send the data to the server. This significantly improves performance, especially in forms with many inputs, by minimizing unnecessary network requests.

In Livewire 2, wire:model was "live" by default – every keystroke or change triggered a server roundtrip. This could lead to performance bottlenecks, particularly with frequent updates. Livewire 3's default behavior prioritizes efficiency, but it requires us to explicitly indicate when we need instantaneous updates.

Building a Dynamic Country/City Selector

Let's build a practical example: a country/city selection for a job application form. When the user selects a country, the city dropdown should immediately update with the relevant cities.

<?php

namespace App\Livewire;

use Livewire\Component;
use App\Models\Country;
use App\Models\City;

class LocationFilter extends Component
{
    public $selectedCountry = null;
    public $cities = [];

    public function render()
    {
        return view('livewire.location-filter', [
            'countries' => Country::all(),
        ]);
    }

    public function updatedSelectedCountry($value)
    {
        // Fetch cities based on the selected country
        $this->cities = $value ? City::where('country_id', $value)->get() : [];
    }
}

The Blade view (location-filter.blade.php):

<div>
    <label for="country">Country:</label>
    <select wire:model.live="selectedCountry" id="country">
        <option value="">Select a Country</option>
        @foreach ($countries as $country)
            <option value="{{ $country->id }}">{{ $country->name }}</option>
        @endforeach
    </select>

    @if ($selectedCountry)
        <label for="city">City:</label>
        <select wire:model="selectedCity" id="city">
            <option value="">Select a City</option>
            {{-- Options are loaded from the $cities property --}}
            @foreach ($cities as $city)
                <option value="{{ $city->id }}">{{ $city->name }}</option>
            @endforeach
        </select>
    @endif
</div>

Key points in this implementation:

  • wire:model.live="selectedCountry": This is the critical part. The .live modifier ensures that whenever the user changes the country selection, the selectedCountry property in our component is immediately updated.
  • updatedSelectedCountry: This is called after selectedCountry is updated. Inside this method, we fetch the cities associated with the selected country from the database.
  • Database Models: This example assumes existence Country and City models, with a country_id foreign key in the City model to establish the relationship. A simple database migration and Eloquent relationship setup would handle this.

The Importance of .live

Without wire:model.live on the country select, the $selectedCountry property in your component would not update when the user changes the selection because updatedSelectedCountry method wouldn't be called, and the city dropdown would remain empty or show incorrect data. It would be a broken user experience.

.live makes the updates to the dropdown to be communicated to the server i real time, providing immediate feedback and a smooth, intuitive user interaction. Sometimes you may want to use .live explicitly because it clearly communicates the intent. Any developer looking at this code will instantly understand that the country dropdown should trigger real-time updates.

Conclusion:

Understanding wire:model.live is essential for building dynamic and responsive forms in Livewire 3. It represents a shift towards greater performance by default, but it empowers you to choose when real-time updates are crucial for the user experience. By embracing .live strategically, you can create fast, interactive forms that enhance your Livewire applications.

For further exploration, consider looking into Livewire's other modifiers like .debounce and .blur, which offer additional control over when data is synchronized with your component.

Wanna chat about what you just read, or anything at all? Click here to tweet at me on 𝕏