DEV Community

George Tudor
George Tudor

Posted on

Event driven Livewire components

Livewire is a really popular library for Laravel which I really love and use across all my projects. It provides that sweet SPA feeling while using almost no Javascript. For me... it's magic. :)

Simple vs complex functionality

Building some forms or having some small actions is pretty straightforward to do in Livewire and doesn't introduce any complexity. You just do it in one component.

But sometimes you have to deal with multiple actions that have to happen in a specific sequence or have to pass data from one to another. You can still do this inside a single component but this is not something I like to do due to various reasons. I believe it's better to split your code into as many components as possible because it's easier to maintain them and the probably some components can also reused if you introduce some kind of abstraction.

When you split your code into multiple components and those components have to communicate between each other then you definitely need to use events.

Using events in Livewire

Livewire events are split into 2 categories: server events and browser events.

We're going to talk talk strictly about server events because using those we can pass data from one component to another.

You can emit server events to any other component, to a specific component, to parent components and even to the same component the event was emitted from.

Let's look at a simple example that uses 2 components: one for input and one for displaying data.

use Livewire\Component;

class InputForm extends Component
{
    public string $input = '';

    public function add() {
        $this->validate([
            'input' => 'required|string'
        ]);

        $this->emit('input-form-submitted', $this->input);
        $this->reset(['input']);
    }

    public function render() {
        return view('livewire.input-form');
    }
}
Enter fullscreen mode Exit fullscreen mode

input-form view:

<div>
    <input type="text" wire:model.defer="input" />
    <button wire:click="add">Add</button>
</div>
Enter fullscreen mode Exit fullscreen mode

So anytime we fill in our input and press the "Add" button we validate the input, emit an event and pass the input's value and then reset the $input to its original value.

Now in our second component we have to listen for this event and display the data into a list.

use Livewire\Component;

class DataViewer extends Component
{
    public array $data = [];

    protected $listeners = [
        'input-form-submitted' => 'updateData'
    ];

    public function updateData(string $data) {
        $this->data[] = $data;
    }

    public function remove(int $index) {
        unset($this->data[$index]);
    }

    public function render() {
        return view('livewire.data-viewer');
    }
}
Enter fullscreen mode Exit fullscreen mode

data-viewer view:

<div>
    <ul>
        @foreach($data as $key => $item)
            <li>
                <span>{{ $item }}</span>
                <button wire:click="remove('{{ $key }}')">Remove</button>
            <li>
        @endforeach
    </ul>
</div>
Enter fullscreen mode Exit fullscreen mode

So now, every time we detect a new event called input-form-submitted in our 2nd component the updateData function is getting called which appends the received data to the list.

In this way we can reuse the 2nd component somewhere else, if needed.

Hope you've enjoyed this quick example and you understand the whole idea of splitting components whenever a complex functionality is required.

Top comments (0)