I'm following a tutorial to add infinity scroll with livewire, there's other approaches that's working but this one is different because it's using cursorPaginate and pushes the data to a collection. so instead of querying all the data each time you push new data to a collection.
class HomePage extends Component
{
public $posts; // holds are list of posts.
public $nextCursor; // holds our current page position.
public $hasMorePages;
/**
* Initialize data
* @return void
*/
public function mount()
{
$this->posts = collect(); // initialize the data
$this->loadPosts(); // load the data
}
/**
* Load data and maintain cursor state
*
*/
public function loadPosts()
{
if ($this->hasMorePages !== null && !$this->hasMorePages) {
return;
}
$posts = Post::cursorPaginate(
5,
['*'],
'cursor',
Cursor::fromEncoded($this->nextCursor)
);
$this->posts->push(...$posts->items());
$this->hasMorePages = $posts->hasMorePages();
if ($this->hasMorePages === true) {
$this->nextCursor = $posts->nextCursor()->encode();
}
}
}
the first call is woking as expected and returning the collection below:
Illuminate\Support\Collection {#1190 ▼
#items: array:5 [▼
0 => App\Models\Post {#1742 ▶}
1 => App\Models\Post {#1740 ▶}
2 => App\Models\Post {#1739 ▶}
3 => App\Models\Post {#1738 ▶}
4 => App\Models\Post {#1737 ▶}
]
#escapeWhenCastingToString: false
}
but when I scroll or do the second call. the old values are changed to array and then appending the new collection, the second call returns like that:
^ Illuminate\Support\Collection {#1178 ▼
#items: array:10 [▼
0 => array:18 [▶]
1 => array:18 [▶]
2 => array:18 [▶]
3 => array:18 [▶]
4 => array:17 [▶]
5 => App\Models\Post {#1760 ▶}
6 => App\Models\Post {#1758 ▶}
7 => App\Models\Post {#1757 ▶}
8 => App\Models\Post {#1756 ▶}
9 => App\Models\Post {#1755 ▶}
]
#escapeWhenCastingToString: false
}
what I have tried so far:
1- instead of pushing all the items I iterate through each item and then push it to the collection:
foreach($posts->items() as $item){
$this->posts->push($item);
}
2- instead of using collection using array:
public $posts = [];
foreach($posts->items() as $item){
array_push($this->posts, $item);
}
and others that I don't remember.
the strange thing is they are all returning the same thing for the first call and the second call, I have debugged the $posts variable for the first call and the second call they both return collections without issues. the change happens only when pushing for the second time. and the blade of course is like that:
@foreach($posts as $post)
<livewire:post-card :post="$post" :loop_index="$loop->index" wire:key="{{$loop->index}}"/>
@endforeach
@if($hasMorePages)
<div
x-data="{
init () {
let observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
@this.call('loadPosts')
}
})
}, {
root: null
});
observer.observe(this.$el);
}
}"
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 mt-4"
>
@foreach(range(1, 4) as $x)
@include('components.skeleton')
@endforeach
</div>
@endif