Scenario
What i try to do
I am creating a multicolumn user index page, where the right column shows details from the user selected in the left column. When selected, the user is not pulled out of the collection but freshly out of the database, so the data is up to date.
I defer the loading of the user list using the described method in the livewire documentation.
The user has a 'roles' relationship, which is displayed in the list column.
What I'd expect
I would expect that once the $this→users is set as a collection of the users and a user is selected, only the query will fire for getting the data for this user.
What actually happens
When a user is selected, a query for getting all users from the database is run (again), and because of the fact that the roles from the user are displayed in the list view, for each user, a new query is executed. After that, a query for getting the selected user is executed. Afterwards another query for getting the roles of the user is fired to.
So my questions
- Why does Livewire lose the relations that were eager loaded in the first declaration of public $users?
- Why is it that Livewire reruns the query for getting all users, while the public $users is already defined as a collection of users?
Files:
- UserListDetail.php
<?php
namespace App\Http\Livewire;
use App\Models\User;
use Livewire\Component;
class UsersListDetail extends Component {
public string $search = '';
public $users;
public $selectedUser;
public int $timesRun = 0;
public bool $readyToLoadUserList = false;
protected $queryString = [
'search' => [ 'except' => '' ],
];
// Defer loading users
public function readyToLoadUserList()
{
// Get all users with roles relationship
$this->users = User::with('roles')->get();
$this->readyToLoadUserList = true;
}
public function selectUser(int $userId)
{
$this->selectedUser = User::with('roles')->find($userId);
}
public function render()
{
return view('livewire.users-list-detail', [
'selectedUser' => $this->selectedUser,
]
);
}
}
- simplified version of user-list-detail.blade.php
<div>
<div wire:init="readyToLoadUserList">
@if($readyToLoadUserList)
<ul>
@foreach($users as $user)
<li wire:click="selectUser({{ $user->id }})">
{{ $user→name_first }} {{ $user→name_last }},
@foreach($user→roles as $role)
{{ $role→label }},
@endforeach
</li>
@endforeach
</ul>
@endif
</div>
<div>
@isset($selectedUser)
{{ $name_first
@endisset
</div>
</div>