property does not refresh in the internal components of Livewire

Viewed 1193

Take a look at the following examples:

showPost.blade.php:

<div>
    <livewire:content-box :content="$post"/>

    <button wire:click="nextPost" >Next Post >></button>
</div>

and content-box.blade.php :

<div>
    <h1>{{ $content->title }}</h1>
    <p>{{ $content->content }}</p>
</div>

So far, it is completely clear what is going to happen ...: First, the information of the content to be viewed is received through showPost and passed to the contentBox, and everything is OK ..

Well now I want to get the information of the next content via the account through the button I put and calling the nextPost method:


class ShowPost extends Component
{
    public Post $post;

    public function render()
    {

        return view('livewire.show-post');
    }

    public function nextPost()   
    {
        $id = $this->post->id;
        $nextPost = Post::where('id', '>', $id)->first();
        $this->post = $nextPost;
    }

...

But nothing happens and the contentBox component has no reaction .... Has anyone had this problem ???!

2 Answers

I'm not sure livewire works well with nested components. could use the pagination instead. The livewire docs suggest you should not use them for little snippets or use blade components for that kind of nesting.

You can achieve what you're doing at the moment with some simple pagination.

<?php

namespace App\Http\Livewire;

use App\Models\User;
use Livewire\Component;
use Livewire\WithPagination;

class SomeContent extends Component
{
    use WithPagination;

    public function render()
    {
        // Using simplePaginate(1) instead of paginate(1).
        // simplePaginate only shows "<- Previous" and "Next ->" links 
        // paginate shows those 2 buttons but also page numbers which you don't seem to want.
        return view('livewire.some-content', [
            'users' => User::simplePaginate(1),
        ]);
    }
}
<div>
    {{-- This might look wrong, but essentially it's looping through an array of length 1 because we're paginating --}}
    @foreach ($users as $user)
        <h1>{{ $user->name }}</h1>
        <h2>{{ $user->email }}</h2>
    @endforeach
    {!! $users->links() !!}
</div>

EDIT

I can confirm blade components work.

Here, nextUser is the same implementation you gave.

    public function nextUser()   
    {
        $id = $this->user->id;
        $nextUser = User::where('id', '>', $id)->first();
        $this->user = $nextUser;
    }
<div class="container">
    <div class="content">
        {{-- These two have the exact same template --}}
        <livewire:child :user="$user" />{{-- Doesn't update when clicking Next --}}
        <x-blade-child  :user="$user" />{{-- Updates when clicking Next --}}
    </div>
    <div>
        <button wire:click="nextUser">Next</button>
    </div>
</div>

When clicking nextUser, the blade component updates but the livewire one doesn't.

Livewire doesn't like nested components. In your case, we can use basic blade component:

<div>
    <x-content-box :content="$post"/>

    <button wire:click="nextPost" >Next Post >></button>
</div>

And then:

  1. Move content-box.blade.php to resources/views/components/
  2. Remove component_name.php file in app/Http/Livewire

Most of the time, we can change 2 nested livewire components to livewire(parent) + basic blade component(child),

Related