Infinite scroll

Merge pages of items and report paging metadata to the InfiniteScroll client component.

On this page

Use infinite scroll when a reader should see more items as they reach the end of a list. Scroll(...) merges the items inside a value (the wrapper, "data" by default) and reports paging metadata to the <InfiniteScroll> client component.

Text
app.MapGet("/feed", (PageRequest request) => Render("Feed", new InertiaProps
{
    ["posts"] = Scroll(Pagination.Paginate(AppState.Posts, request)),
}));
Text
{
  "props": { "errors": {}, "posts": { "data": [ { "id": 21 } ] } },
  "mergeProps": ["posts.data"],
  "scrollProps": {
    "posts": { "pageName": "page", "previousPage": 1, "nextPage": 3, "currentPage": 2, "reset": false }
  }
}

See Pagination for numbered and cursor pages, query binding and data-source delegates.

The client

Text
import { InfiniteScroll } from '@inertiajs/react'

<InfiniteScroll data="posts">
  {posts.data.map((post) => <Post key={post.id} post={post} />)}
</InfiniteScroll>

Metadata

ScrollMetadata(PageName, PreviousPage, NextPage, CurrentPage) is a record. Page values can be int, long, string or null (cursor paging uses strings).

Metadata comes from the metadata: argument, or from the value if it implements IProvidesScrollMetadata. Without either, the render throws with a message naming the prop.

Text
["posts"] = Scroll(page, wrapper: "data", metadata: ScrollMetadata.FromPage(2, hasMore: true)),

The client sends X-Inertia-Infinite-Scroll-Merge-Intent: prepend when scrolling up. The wrapper is then reported under prependProps instead of mergeProps.

scrollProps[path].reset is true when the request lists the path in X-Inertia-Reset.

Combining with other props

Scroll(...) accepts the five loader shapes, and .Defer(), .Once() and .Rescue() combine with it:

Text
["posts"] = Scroll(ct => feed.PageAsync(1, ct)).Defer(),

A deferred scroll prop reports "posts.data" just like a resolved one. This is a deliberate fix of an inertia-laravel quirk.

Keep pages small

Infinite scroll is also a payload-size tool. Load 10 to 20 items per page instead of sending an unbounded list on the first request.