#Pagination function doesn't appear to be passing content collection data

3 messages · Page 1 of 1 (latest)

waxen merlin
#

I'm upgrading a site from using Markdown files in src/pages to content collections. The blog page uses Pagination to generate a list of pages. The existing code (which I didn't write, so I'm only somewhat familiar with it) starts with the pagination function, which passes its results to a <Paginator /> component, which passes each Page<T>.data[] element to a <PostEmbed /> element, which creates each list item on the page.

This is the pagination function:

// src/pages/blog/[page].astro
export async function getStaticPaths({ paginate }: any) {
    const allPosts = await getCollection("blog")
    sortByDescending(allPosts, (post) => new Date(post.data.date));

    return paginate(allPosts, { pageSize: 5 });
}

The docs say that the paginate function returns its data as Page<T>, so I've typed Astro.props as follows:

// src/pages/blog/[page].astro
export interface Props {
  page: Page<CollectionEntry<"blog">>
}

Then I've passed the prop to the paginator as <Paginator page={Astro.props.page} /> and <Paginator />'s Props are typed as above.

In Paginator.astro, each entry in the collection is mapped to a <PostEmbed />:

// Paginator.astro
{page.data.map((post) => <PostEmbed {post} />)}

And its Props are typed as follows:

interface Props {
    post: CollectionEntry<"blog">
}

As far as I can tell, this is typed correctly, but when I try visit the page in the dev server, it fails with [ERROR] Cannot destructure property 'title' of 'post.data' as it is undefined.. I tried tracing the data's path through the stack with logging statements like

console.log("PostEmbed received: " + JSON.stringify(Astro.props))

to see what Astro.props.post is actually sending, but nothing was printed to the console, so I'm not really sure where to go next.

Docs

An intro to routing with Astro.

hexed spear
#

Hi! From that, I'm not sure what went wrong but I can see a few things that could help to avoid mismatch between types and the expected output (which could help narrow what is going wrong here):

  1. When using getStaticPaths, you don't need to define Props manually, they can be automatically inferred (which can help avoid unexpected types errors):
---
import type { GetStaticPaths } from "astro";

export const getStaticPaths = (async ({ paginate }) => {
  /* the logic */
}) satisfies GetStaticPaths;

const { page, /* your other props */ } = Astro.props; // You should have the proper types for `page` and your other props here!
---

See: https://docs.astro.build/en/guides/typescript/#infer-getstaticpaths-types

But, if you prefer to type things manually, you should be able to import GetStaticPathsOptions instead of using any.

  1. Your sortByDescending returns nothing? Is it meant to mutate allPosts? You might need to use let allPosts instead of const allPosts. But, personnally, I would recommend to return a value and assign it to a new variable:
import type { GetStaticPaths } from "astro";

export const getStaticPaths = (async ({ paginate }) => {
    const allPosts = await getCollection("blog")
    const sortedPosts = sortByDescending(allPosts, (post) => new Date(post.data.date));

    return paginate(sortedPosts, { pageSize: 5 });
}) satisfies GetStaticPaths;

Now regarding your issue:

  • "nothing was printed to the console", not even PostEmbed received: or do you mean you had nothing after that?
  • are you sure your collection is properly defined? I mean, does await getCollection("blog") returns something or do you see a warning in the console telling you the collection is empty?
  • if you add a console.log("page", Astro.props.page) in src/pages/blog/[page].astro, do you see your data? If so, we might need to see Paginator to understand what happens!
Docs

Learn how to use Astro's built-in TypeScript support.

waxen merlin
#

But, if you prefer to type things manually
I do not, thanks for the tip!

Thanks so much for such a detailed response - writing my reply made me realise what has happened. The <PostEmbed /> component is being used elsewhere on the site and I hadn't upgraded that implementation to use content collections yet. The problem turned out not to be the code I wrote, just the code I haven't written yet! 😄