entropy
entropy8mo ago

preloaded data with paginated query

Hello, I was wondering if there was an official way of preload loading data for a paginated query in nextjs? With regular queries I can just use the usePreloadedQuery() hook, but I don't see an equivalent for paginated queries.
5 Replies
entropy
entropyOP8mo ago
anime/page.tsx
const preloadedAnime = await preloadQuery(api.functions.anime.list, {
paginationOpts: { numItems: 5, cursor: null }
})
const preloadedAnime = await preloadQuery(api.functions.anime.list, {
paginationOpts: { numItems: 5, cursor: null }
})
anime/_components/anime-list.tsx
const preloadedResults = usePreloadedQuery(preloadedAnime).page
const { results, status, loadMore } = usePaginatedQuery(
api.functions.anime.list,
{},
{ initialNumItems: 5 }
)

return (
<div>
{(preloadedResults || results)?.map(anime => (
// component stuff...
))}
</div>
)
const preloadedResults = usePreloadedQuery(preloadedAnime).page
const { results, status, loadMore } = usePaginatedQuery(
api.functions.anime.list,
{},
{ initialNumItems: 5 }
)

return (
<div>
{(preloadedResults || results)?.map(anime => (
// component stuff...
))}
</div>
)
Here's what I've come up with but I'm not sure if this is what is intended to be done. edit: I've realize this approach wouldn't work with the load more function. I've ended up with this which seems to work well enough.
const preloadedResults = usePreloadedQuery(preloadedAnime).page
const {
results: queryResults,
status,
loadMore,
isLoading
} = usePaginatedQuery(api.functions.anime.list, {}, { initialNumItems: 5 })

const [results, setResults] = useState(preloadedResults ?? queryResults)
useEffect(() => {
if (!isLoading) setResults(queryResults)
}, [queryResults, isLoading])

return (
<div>
{results.map(anime => (
// component stuff...
))}
</div>
)
const preloadedResults = usePreloadedQuery(preloadedAnime).page
const {
results: queryResults,
status,
loadMore,
isLoading
} = usePaginatedQuery(api.functions.anime.list, {}, { initialNumItems: 5 })

const [results, setResults] = useState(preloadedResults ?? queryResults)
useEffect(() => {
if (!isLoading) setResults(queryResults)
}, [queryResults, isLoading])

return (
<div>
{results.map(anime => (
// component stuff...
))}
</div>
)
@ballingt @ian would you have any insights on this?
ian
ian8mo ago
Yeah I think that's a good approach. You could maybe replace the useState / useEffect with a ref:
function useLatest<T>(initial: T, value: T, replace: boolean) {
const r = useRef(initial);
if (replace) {
r.current = value;
}
return r.current;
}



const results = useLatest(preloadedResults, queryResults, !isLoading);
function useLatest<T>(initial: T, value: T, replace: boolean) {
const r = useRef(initial);
if (replace) {
r.current = value;
}
return r.current;
}



const results = useLatest(preloadedResults, queryResults, !isLoading);
Though I haven't used / tested this
entropy
entropyOP8mo ago
hmm interesting will definitely take a look at this. Thank you for the info as always!
Michal Srb
Michal Srb8mo ago
I think you need neither useEffect nor useRef:
const preloadedResults = usePreloadedQuery(preloadedAnime).page;
const { results: paginatedResults, status, loadMore } = usePaginatedQuery(
api.functions.anime.list,
{},
{ initialNumItems: 5 }
);
const results = status === "LoadingFirstPage"
? preloadedResults
: paginatedResults;

return (
<div>
{results.map(anime => (
// component stuff...
))}
</div>
)
const preloadedResults = usePreloadedQuery(preloadedAnime).page;
const { results: paginatedResults, status, loadMore } = usePaginatedQuery(
api.functions.anime.list,
{},
{ initialNumItems: 5 }
);
const results = status === "LoadingFirstPage"
? preloadedResults
: paginatedResults;

return (
<div>
{results.map(anime => (
// component stuff...
))}
</div>
)
Give it a go and let us know if it works.
entropy
entropyOP8mo ago
Yep that works perfectly, thank you for the great suggestion!

Did you find this page helpful?