Can not nest components and keep reactivity - roadmap?

I’m really enjoying Livewire as I migrate the SAAS behind SchoolTwist.com from WordPress to Laravel. But I’m running into this limitation, and I’m wondering if I’m missing the bigger picture.
I experimented with livewire loading large blades when I clicked on various admin sidbar entries and sub-tabs in the body. It worked great until I ran into (documented) limitation that nested components can’t have reactivity.

To me, this means every page must be a monolithic layout in order to get the primary benefits of livewire. In practice, I found this to be a show-stopper towards using livewire to load chunks of page (but it works great for polling small-and-reactive components.

I wanted, for example, to create an ajax-populated modal with livewire components, but it didn’t seem possible unless I totally backed out of livewire for everything else on the containing page. In other words, a livewire component couldn’t dynamically load other components.

So, I’m not really really trying to solve this problem, since it is a documented limitation.

Do we think this no-cascading-reactivity limitation will ever be removed? Is it on the ‘roadmap’?

You should look into events and listeners within livewire. I’ve been using them to great effect on a single-page app. The event will fire and only the component listening for that event will need to be re-rendered. This keeps your layout in tact and doesn’t require the whole page to be refreshed.

One example component that encompasses this is my modal:

Modal.php

namespace App\Http\Livewire;

use Livewire\Component;

class Modal extends Component
{
    public $show = false;
    public $message = '';
    public $dialog = '';

    protected $listeners = ['showLibrary', 'hideModal', 'addBoard'];

    public function render()
    {
        return view('livewire.modal');
    }

    public function showLibrary()
    {
        $this->dialog = 'library';
        $this->show = true;
    }

    public function addBoard()
    {
        $this->dialog = 'addBoard';
        $this->show = true;
    }

    public function hideModal()
    {
        $this->dialog = '';
        $this->show = false;
        $this->dispatchBrowserEvent('hide-modal');
    }

}
modal.blade.php

<div x-show="modal" @if(!$show) style="display:none;" @endif>
    <div @click="modal = false">
        <div></div>
    </div>
    <div wire:loading>loading...</div>
    @if($show)
    @if($dialog == 'library')
    <livewire:library />
    @endif
    @if($dialog == 'addBoard')
    <livewire:add-board />
    @endif
    @endif
</div>

This code dynamically loads different modals based on what’s being triggered. The livewire component just sits at the bottom of my view.

Edit: removed styling for clarity.

1 Like

I was using listeners, but in your example, I would expect to NOT be able to embed more livewire components inside of ‘library’.
When I tried this, I was able to add another embedded component, but the nested component would lack liveware awareness (The html would render, but new livewire logic didn’t work).

I have livewire components within library. They’re buttons that have wire:click attached and function as expected.

Hmm - perhaps the mistake was on my end. The docs (https://laravel-livewire.com/docs/nesting-components) say Nested components CAN accept data parameters from their parents, HOWEVER they are not reactive like props from a Vue component. I guess I’m hoping for clarification on what, precisely this means?

I’ll try to create a concise example that demonstrates the effect.

Concise examples would help clarify things. If you really need that kind of reactivity, you may just have to go with Vue. However, I think Livewire can create an SPA fairly well. You just have to work within the framework’s limitations.

It means a public property in the parent component is not accessible in the child component. You can pass it into the mount of the child component, but they are not tied together, eg if you make a change to the child’s property that stemmed from the parent, the parent’s property will not change.

I made some stand-alone examples for myself, and it seems more functional than I originally thought. I have a theory that my original work had a parameter error that was dying silently and I misdiagnosed the problem.
While working on my stand-along example, a missing closing inner-quote produced some similar results.

Still it is possible to pass data (property value) via specific events after mounting. It will cause a re-rendering of the parent (in your case), but works.

I was answering HOWEVER they are not reactive like props from a Vue component. meaning you have to manually keep the two properties synced together (with the database, cache, session, events, etc). You can not treat them like a single source object in memory being accessed by two components because there is no true memory state with php like you can do in javascript. Livewire helps emulate state, but at the end of the day it’s just that, emulation.