Merging Props¶
Combine new data with existing props for infinite scroll and live updates.
See also
Official Inertia.js docs: Merging Props
The merge() Helper¶
Use merge() to append or prepend data instead of replacing:
from litestar_vite.inertia import merge
@get("/posts", component="Posts")
async def list_posts(page: int = 1) -> dict:
posts = await Post.paginate(page=page, per_page=20)
return {
"posts": merge("posts", posts.items), # Append to existing
}
Merge Strategies¶
# Append new items to end (default)
merge("posts", new_posts)
merge("posts", new_posts, strategy="append")
# Prepend new items to beginning
merge("messages", new_messages, strategy="prepend")
# Deep merge nested objects
merge("settings", updated_settings, strategy="deep")
Match On Key¶
Update existing items instead of duplicating:
# Match items by ID - updates existing, appends new
merge("posts", updated_posts, match_on="id")
# Match on multiple keys
merge("items", items, match_on=["type", "id"])
Infinite Scroll¶
Complete infinite scroll example:
Backend¶
from litestar_vite.inertia import merge, scroll_props
@get("/posts", component="Posts")
async def list_posts(page: int = 1) -> dict:
posts = await Post.paginate(page=page, per_page=20)
return {
"posts": merge("posts", posts.items),
"pagination": scroll_props(
page_name="page",
current_page=page,
previous_page=page - 1 if page > 1 else None,
next_page=page + 1 if posts.has_next else None,
),
}
Frontend¶
import { usePage, router, WhenVisible } from "@inertiajs/react";
interface Props {
posts: Post[];
pagination: {
nextPageUrl?: string;
};
}
export default function Posts({ posts, pagination }: Props) {
return (
<div>
{posts.map((post) => (
<PostCard key={post.id} post={post} />
))}
{pagination.nextPageUrl && (
<WhenVisible
always
params={{ only: ["posts"], data: { page: currentPage + 1 } }}
>
<Spinner />
</WhenVisible>
)}
</div>
);
}
<script setup>
import { router, WhenVisible } from "@inertiajs/vue3";
const props = defineProps<{
posts: Post[];
pagination: { nextPageUrl?: string };
}>();
</script>
<template>
<div>
<PostCard v-for="post in posts" :key="post.id" :post="post" />
<WhenVisible
v-if="pagination.nextPageUrl"
always
:params="{ only: ['posts'], data: { page: currentPage + 1 } }"
>
<Spinner />
</WhenVisible>
</div>
</template>
scroll_props() Helper¶
Create pagination metadata for infinite scroll:
from litestar_vite.inertia import scroll_props
scroll_props(
page_name="page", # Query parameter name
current_page=1, # Current page number
previous_page=None, # None if at first page
next_page=2, # None if at last page
)
Automatic Pagination¶
Return pagination objects directly - items and scroll props are extracted:
from litestar.pagination import OffsetPagination
@get("/posts", component="Posts", infinite_scroll=True)
async def list_posts(offset: int = 0, limit: int = 20) -> OffsetPagination:
posts, total = await Post.paginate(offset, limit)
return OffsetPagination(items=posts, offset=offset, limit=limit, total=total)
The infinite_scroll=True opt enables automatic scroll_props extraction.
Supported pagination types:
litestar.pagination.OffsetPagination-items,limit,offset,totallitestar.pagination.ClassicPagination-items,page_size,current_page,total_pagesadvanced_alchemy.service.OffsetPagination- same as Litestar OffsetPaginationAny object with an
itemsattribute and pagination metadata
The pagination container is automatically unwrapped:
itemsattribute is extracted and used as the prop valueIf
infinite_scroll=Trueon the route,scroll_propsis calculated from pagination metadataProp key defaults to
"items"but can be customized withkeyopt
@get("/posts", component="Posts", infinite_scroll=True, key="posts")
async def list_posts(offset: int = 0) -> OffsetPagination:
... # Props will have "posts" instead of "items"
Protocol Response¶
Merge props are indicated in the response:
{
"component": "Posts",
"props": {"posts": ["Post 1", "Post 2"]},
"mergeProps": ["posts"],
"scrollRegion": {
"pageName": "page",
"currentPage": 1,
"nextPageUrl": "/posts?page=2"
}
}
See Also¶
Partial Reloads - Partial reload mechanics
Deferred Props - Deferred loading