livewire: @entangle causes x-init to happen multiple times

When I have @entangle on my alpine components, their x-init happens every time I change the value. I don’t think that’s expected right? In some cases it doesn’t introduce bugs, but sometimes I do heavy things on init, and sometimes really bad bugs are introduced because of this, like when you initialize a rich text editor multiple times every time you type a character.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 26 (17 by maintainers)

Most upvoted comments

I have this issue, even though I’m not using @entangle. I’ve narrowed it down to a nested/child component.

See here:

https://laravelplayground.com/#/snippets/5e812c86-b8f8-4f9e-9796-344224766803

If you have a nested alpinejs scope with x-init, and livewire renders the top/parent component, x-init will re-run every time on the child.

I believe recent $wire fix also applies to this issue. Please update Alpine to 2.8.2 to get the fix (there is no Livewire update needed).

Let me know if it doesn’t and I will reopen 🙂

Hope this helps!

@ryangjchandler Thanks for you answer.

I’m currently using nested components for a modal that has @entangle('show') which I think is a legit use-case. And inside that modal I have custom date pickers, markdown editors, and other stuff that are their own components and can’t share their state with the modal. I think if you’re componentizing your app, there are a million cases where you would have nested components, and we have to see what the intuitive expected behaviour is and achieve that. Here, re-initialization doesn’t seem expected.

Also, if we put wire:ignore on the whole modal in my example, the re-initialization problem is of course fixed since Livewire doesn’t touch is, but that’s not an option for me because it also disables my real time validation messages in the modal and other functionalities that I need, like auto completes, etc.

I also have it I see. Seems to happen on my end because the component is shown conditionally. When I show the component unconditionally x-init is not called multiple times in my case.

I have noticed this (or very similar issue) here and there, particular while using the jetstream-y modal dialogs with color pickers, date pickers, etc., where you end up with nested x-data. You can actually reproduce in the livewire/surge demo if you place a console.log message in the x-init script for the Pikaday date picker component in the edit modal; the date picker is init-ed repeatedly as you show/hide the modal. If you try to get fancy with $watch callbacks, etc., in these cases, it can get ugly.

For me, if I call the following component in a vanilla TALL stack and click the “Button Counter” button, I can see that the Inner init is fired off repeatedly. Is that expected? I feel like if I understood why, then it might steer me in the right direction to have inits just run once … ?

<livewire:nasty-nesty />

namespace App\Http\Livewire;

use Livewire\Component;

class NastyNesty extends Component
{
    public $counter = 0;

    public function increment()
    {
    	$this->counter++;
    }

    public function render()
    {
        return <<<'blade'
            <div x-data x-init="console.log('Outer init just once please')">
	            <div x-data x-init="console.log('Inner init just once please')">
	                <button wire:click="increment">Button Counter {{ $counter }}</button>
	            </div>
            </div>
        blade;
    }
}

@ryangjchandler tried wire:ignore.self and it doesn’t work. Only wire:ignore does and it breaks everything else.

Also, my previous comment about avoiding nested components was more related to when you need to share data between a parent and child.

Sure, I wouldn’t break it into parent and child in that case.