Search code examples
javascriptnext.jsstrapi

How to get paths in getStaticPaths with locales in Next.js?


I'm using Strapi as a CMS, where I query for slugs, and I would like to have statically generated pages using getStaticPaths and getStaticProps in Next.js.

As I need to work with multiple locales, I have to map through the locales and get paths for each "Announcements" I'm getting from my query.

The error message I'm getting is:

Error: A required parameter (slug) was not provided as a string in getStaticPaths for /updates/announcements/[slug]

This is my getStaticPaths:

export async function getStaticPaths({ locales }: any) {
  const paths = await (
    await Promise.all(
      locales.map(async (locale: any) => {
        const { data } = await client.query({
          query: gql`
            query Announcements {
              announcements(locale: "${locale}") {
                data {
                  attributes {
                    slug
                    locale
                  }
                }
              }
            }
          `,
        });
        return {
          announcements: data.announcements.data,
          locale,
        };
      })
    )
  ).reduce((acc, item) => {
    item.announcements.map((p: any) => {
      acc.push({
        params: {
          slug:
            p.attributes.slug === "/" ? false : p.attributes.slug.split("/"),
        },
        locale: p.attributes.locale,
      });
      return p;
    });
    return acc;
  }, []);

  return {
    paths,
    fallback: false,
  };
}

If I console.log(paths) I get the following in the terminal:

[
  { params: { slug: [Array] }, locale: 'en' },
  { params: { slug: [Array] }, locale: 'en' },
  { params: { slug: [Array] }, locale: 'en' },
  { params: { slug: [Array] }, locale: 'da' },
  { params: { slug: [Array] }, locale: 'sv' },
  { params: { slug: [Array] }, locale: 'nb' }
]

I might think that Next.js don't want the slug to be an array, but I'm not entirely sure. What am I doing wrong?


Solution

  • You page uses dynamic routes named (/updates/announcements/[slug]), therefore the param slug is required in paths.

    From the Next.js getStaticPaths documentation:

    The paths key determines which paths will be pre-rendered. For example, suppose that you have a page that uses Dynamic Routes named pages/posts/[id].js. If you export getStaticPaths from this page and return the following for paths:

    return {
     paths: [
       { params: { id: '1' }},
       {
         params: { id: '2' },
         // with i18n configured the locale for the path can be returned as well
         locale: "en",
       },
     ],
     fallback: ...
    }
    

    Then, Next.js will statically generate /posts/1 and /posts/2 during next build using the page component in pages/posts/[id].js.

    The slug param can only be a string since it's used to generate routes. As you found when logging paths, you were trying to pass slug: [Array].

    The problem in the question's code snippet is this expression to assign a slug:

    // ...
    params: {
      slug: p.attributes.slug === "/" ? false : p.attributes.slug.split("/"), // 👈
    },
    // ...
    

    This expression will either assign false (boolean) or an array of substrings (see the docs for String.prototype.split()).

    In this case, as confirmed in a comment above, simply passing the slug as a string solves the issue.

    The confusion likely came from following a tutorial that uses an optional catch-all route (pages/[[...slug]]) instead of regular dynamic routes (pages/[slug]) (ref).

    From the Next.js getStaticPaths documentation again:

    • If the page name is pages/posts/[postId]/[commentId], then params should contain postId and commentId.
    • If the page name uses catch-all routes like pages/[...slug], then params should contain slug (which is an array). If this array is ['hello', 'world'], then Next.js will statically generate the page at /hello/world.
    • If the page uses an optional catch-all route, use null, [], undefined or false to render the root-most route. For example, if you supply slug: false for pages/[[...slug]], Next.js will statically generate the page /.