feat(inertia): add infinite scroll with scroll()#1934
Merged
Conversation
🦋 Changeset detectedLatest commit: 36a2b7b The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Member
|
I didn't know Inertia.js could do something like |
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Final step of the
@hono/inertiav3 protocol breakdown: ④ Infinite scroll, built on top of the merge protocol from #1932.Adds a
scroll()helper that wraps a paginated page payload with the metadata Inertia's<InfiniteScroll>adapter needs to keep loading more items as the user scrolls. The wrapped value travels as-is; the renderer emits a newpage.scrollPropsmap with the previous/next page cursor and opts the prop into the merge protocol so each incoming page is appended (or prepended) to the cached array instead of replacing it.Mirrors
Inertia::scroll(...)in inertia-laravel 3.x.Protocol behaviour
scroll()propscrollProps[key] = { previousPage, nextPage, currentPage, pageName }emitted andmergeProps.push(key)by defaultX-Inertia-Infinite-Scroll-Merge-Intent: prependprependProps.push(key)instead ofmergeProps(the<InfiniteScroll>adapter sends this when scrolling backwards)matchOnpassed (string or array)"<key>.<field>"entry per field appended topage.matchPropsOnfor client-side dedupe; omitted entirely whenmatchOnis not passedonly/exceptscrollProps,mergeProps, ormatchPropsOn)previousPageiscurrentPage - 1(ornullon the first page);nextPageiscurrentPage + 1(ornullon the last page).Implementation
scroll<T>({ data, currentPage, lastPage, pageName, matchOn? }): T[]returns an opaque marker (Symbol.for('@hono/inertia/scroll')) that the renderer unwraps — same pattern asdefer()(feat(inertia): add deferred props with defer() #1911) andmerge()(feat(inertia): add merge props with merge(), prepend(), and deepMerge() #1932). The return type isT[]so call sites andTypedResponsestay transparent.PageObjectgains one optional field,scrollProps?: Record<string, ScrollDescriptor>, whereScrollDescriptor = { previousPage, nextPage, currentPage, pageName }.matchOnis intentionally not part of the descriptor — it travels only viapage.matchPropsOn, matchingInertia\ScrollProp::metadata()in the Laravel adapter.append; the client switches it by sendingX-Inertia-Infinite-Scroll-Merge-Intent: prepend. Unknown header values fall back toappend. MirrorsScrollProp::configureMergeIntentin inertia-laravel.matchOnaccepts a string or string array, optional with no default, matchingInertia::merge(matchOn:)and the existingmerge()helper in this package.Scope intentionally kept small (single PR per protocol feature, like #1904 / #1911 / #1932):
scroll()markermatchOnappend+prependvia the merge-intent headermerge()/prepend()/deepMerge()/defer()in the same responsedata/currentPage/lastPage/pageNameare passed explicitlyTest plan