I would like to create a category page containing all tags added to articles. When clicking on a tag it should show a page with all articles containing that specific tag.
I'm using Next.js, SSG, and fetching the articles from Contentful with the following GraphQL query:
export async function getArticles() {
const articlesQuery = gql`
{
articleCollection {
items {
title
slug
excerpt
date
contentfulMetadata {
tags {
name
id
}
}
featuredImage {
title
url
width
height
}
}
}
}
`;
return graphQLClient.request(articlesQuery);
}
The contentfulMetadata
is where the tags come from:
contentfulMetadata {
tags {
name
id
}
}
I've then created a CategorySection
component:
import styled from "styled-components";
import { getArticles } from "../../utils/contentful";
import Link from "next/link";
export async function getStaticProps() {
const categories = await getArticles();
return {
props: {
categories: categories.articleCollection.items,
},
};
}
export default function CategorySection({ categories }) {
return (
<Wrapper>
<ContentWrapper>
<CategoryWrapper>
{categories.map((category) => {
return (
<Link href={`/articles/categories/${category.tags.name}`}>
<Categories key={category.tags.id}>
{category.tags.name}
</Categories>
</Link>
);
})}
</CategoryWrapper>
</ContentWrapper>
</Wrapper>
);
}
The CategorySection
component gives me the following error message:
TypeError: Cannot read property 'map' of undefined"
Below is my /pages/articles/categories/[slug].jsx
file:
import styled from "styled-components";
import { getArticles, getArticle } from "../../utils/contentful";
export async function getStaticPaths() {
const data = await getArticles();
return {
paths: data.articleCollection.items.map((article) => ({
params: { slug: article.contentfulMetadata.tags.id },
})),
fallback: false,
};
}
export async function getStaticProps(context) {
const data = await getArticle(context.params.slug);
return {
props: { article: data.articleCollection.items[0] },
};
}
export default function Category({ article }) {
return <h1>{article.contentfulMetadata.tags.name}</h1>;
}
I'm getting the error below:
Error: A required parameter (slug) was not provided as a string in getStaticPaths for /articles/categories/[slug]
Can you help me understand how I create dynamic pages from my categories (tags)?
getStaticProps
can only be used in page components, so in your case it'll be completely ignored in your CategorySection
component. You'll need to fetch the data at the page level and pass it to the component where you want to use it.
One possible solution is to simply pass the data as a prop down to the desired component.
// pages/article
import { getArticles } from "../../utils/contentful";
export async function getStaticProps() {
const categories = await getArticles();
return {
props: {
categories: categories.articleCollection.items
}
};
}
export default function ArticlePage({ categories }) {
return (
<CategorySection categories={categories} />
);
}