I learn nextJS and I try to use dynamic routes with a catch-all route. However I'm running into a basic problem, I'm not sure how to supply the data as an array in getStaticPaths.
This is my current code:
import Link from 'next/link';
function test({ variable }) {
return (
<>
<div>
<h1>{variable.var}</h1>
<Link href="/">
<a>← Back</a>
</Link>
</div>
</>
);
}
export async function getStaticProps({ params }) {
const variable = params.variable;
return {
props: {
variable,
},
};
}
export async function getStaticPaths() {
return {
fallback: false,
paths: [
{
params: {
variable: 'testi',
},
},
],
};
}
export default test
And I'm getting the error:
Error: A required parameter (variable) was not provided as an array in getStaticPaths for /test/[...variable]
Any ideas?
Edit:
Forgot to add, my current file name is [...variable].js
Indeed it was stupid:
paths: [
{ params: { variable: ["testi"] } },
]
Related
I just added next-i18next in my nextjs project following the official guide and everything seemed to be in order, but when I change the language from default (Italian) to English and I go to the detail of an entity then I get 404. This happens only with the dynamic routes and only with the language that is not the default one.
I am going to show you more details.
My next-i18next.config.js file:
module.exports = {
i18n: {
defaultLocale: "it",
locales: ["it", "en"],
},
};
[id].tsx
//My NextPage component...
export async function getStaticPaths() {
const paths = await projects.find()?.map((_project) => ({
params: { id: _project.id + "" },
}));
return {
paths,
fallback: false,
};
}
export async function getStaticProps({
locale,
...rest
}: {
locale: string;
params: { id: string };
}) {
const project = await projects.findOne({id: rest.params.id})
const seo: Seo = {
//...
};
//This row is not the problem, since it persists even if I remove it. Also I am sure that the project exists.
if (!project?.id) return { notFound: true };
return {
props: {
...(await serverSideTranslations(locale, [
"common",
"footer",
"projects",
])),
seo,
project,
},
};
}
index.tsx (under projects folder)
const Projects: NextPage<Props> = ({ /*...*/ }) => {
//...
const router = useRouter();
return <button onClick={() =>
router.push({
pathname: `/projects/[slug]`,
query: { slug: project.slug },
})
}>Read more</button>
}
Also I get the error Error: The provided 'href' (/projects/[slug]) value is missing query values (slug) to be interpolated properly. when I try to change the language while I am in the detail of the project with the italian language set, but I think I did it right according to this doc. As I said before, instead, if I try to go into the dynamic route after having changed the language to "en" then I go to 404 page.
Do you have any suggestions to solve this problem?
I solved this by updating the mothod getStaticPaths to:
export async function getStaticPaths({ locales }: { locales: string[] }) {
const projects = getProjects({ locale: "it" });
const paths = projects.flatMap((_project) => {
return locales.map((locale) => {
return {
params: {
type: _project.slug,
slug: _project.slug,
},
locale: locale,
};
});
});
return {
paths,
fallback: true,
};
}
So there must be passed the locale into the paths.
I'm trying to create a multi-directory dynamic URL in Next.js.
A rough example of what I'm trying to accomplish is found here: https://codesandbox.io/s/next-js-forked-5scpgb?file=/page/tools/%5B...path%5D.js.
I'm trying to, for example, create a URL route like 'tools/category-title/tool-slug' based on the seed object provided in the example.
I found the https://nextjs.org/docs/routing/dynamic-routes docs, which notes pages/post/[...slug].js matches /post/a, but also /post/a/b, /post/a/b/c and so on.
However, I've been unsuccessful in trying to get this to work.
Any support would be appreciated!
Code from sandbox repo --
import React from "react";
const toolSeed = [
{
id: 1,
slug: "tool-slug",
category: {
id: 1,
title: "category-title",
}
},
{
id: 2,
slug: "tool-slug-2",
category: {
id: 2,
title: "category-title-2",
},
}
]
export async function getStaticPaths() {
const paths = toolSeed.map((tool) => ({
params: { slug: `${tool.category.title}/${tool.slug}` }, // href={`/${tool.category}/${tool.slug}`}
}));
return {
paths: paths,
fallback: false // render 404 if no match
};
}
export async function getStaticProps({ params }) {
// filter to get the current tool
const tool = toolSeed.filter((obj) => obj.slug === params.slug);
return {
props: { tool },
revalidate: 900 // this tells Next.js to re-generate the page every 15 minutes
};
}
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
export default function Tool ({ tool }) {
console.log('tool')
return (
<></>
)
};
I'm using Next.js with Typescript, and I'm having some troubles to correctly type my props that getServerSideProps would return me. On getServerSideProps, or as I call it, getServerSidePropsImpl, I check user authentication and decide if I give it a redirect or the data for it to initialize. The problem with this is that Typescript doesn't correctly type my props, or give me some errors.
So, i had the idea to :
// /pages/sheet/1.tsx
import React from 'react';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import database from '../../utils/database';
import { sessionSSR } from '../../utils/session';
export default function Sheet1(props: InferGetServerSidePropsType<typeof getServerSidePropsImpl>): JSX.Element {
//...Do some stuff...
return <></>;
}
async function getServerSidePropsImpl(ctx: GetServerSidePropsContext) {
const player = ctx.req.session.player;
if (!player) {
return {
redirect: {
destination: '/',
permanent: false
},
props: {
playerID: 0,
playerInfo: []
}
};
}
const playerID = player.id;
const results = await Promise.all([
database.playerInfo.findMany({
where: {
player_id: playerID
},
select: {
info: true,
value: true
},
})
]);
return {
props: {
playerID,
playerInfo: results[0]
}
};
}
export const getServerSideProps = sessionSSR(getServerSidePropsImpl);
To make sure Typescript would correctly type my props object, I had to put generic values when returning a redirect:
return {
redirect: {
destination: '/',
permanent: false
},
props: {
playerID: 0,
playerInfo: []
}
};
Is there any issues to this approach, giving the amount of props will increase as I make this component?
I'm using Next.js with Static Site Generation, and I've created a category (tags) component as shown below:
import Link from "next/link";
export default function CategorySection({ categories }) {
return (
<Wrapper>
<ContentWrapper>
<CategoryWrapper>
{categories.map((category) => {
return (
<>
{category.contentfulMetadata.tags.map((tag) => {
return (
<Link href={`/articles/categories/${tag.id}`}>
<Categories>{tag.name}</Categories>
</Link>
);
})}
</>
);
})}
</CategoryWrapper>
</ContentWrapper>
</Wrapper>
);
}
I would like to be able to create dynamic pages for all tags and show articles only related to the tag.
I have created my [slug].jsx file at the following location: /pages/articles/categories/[slug].jsx
[slug].jsx file below:
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 get the following error when navigation by using the tags on my articles page:
Error: A required parameter (slug) was not provided as a string in getStaticPaths for /articles/categories/[slug]
How can I get it to create dynamic pages using the tags?
Error: A required parameter (slug) was not provided as a string in getStaticPaths for /articles/categories/[slug]
In your getStaticPaths you need to convert slug to string.
params: { slug: article.contentfulMetadata.tags.id.toString() }
I'm using Next.js and trying to implement incremental static regeneration. My pages structure is:
pages
- [primary]
- article
- [...slug.js]
and my [...slug.js]
import Head from 'next/head'
export default function Article({ post }) {
if (!post) {
return 'loading'
}
const data = post[0];
return (
<div className="container mx-auto pt-6">
<Head>
<title>{`${data.title.rendered}`}</title
</Head>
<main>
<div>{data.content.rendered}</div>
</main>
</div >
)
}
export async function getStaticPaths() {
return {
paths: [{ params: { primary: '', slug: [] } }],
fallback: true,
};
}
export async function getStaticProps({ params }) {
const slug = params.slug[0];
const res = await fetch(`https://.../?slug=${slug}`)
const post = await res.json()
return {
props: { post },
revalidate: 1,
}
}
This works locally when I pass route like: localhost:3000/dance/article/lots-of-dancers-dance-in-unison, it correctly passes the slug and I can query the CMS no problem. But when I run build I get:
Error: Requested and resolved page mismatch: //article /article at normalizePagePath
This is because the static path you are providing for primary is '' (empty).
For empty string value for primary, the static path becomes //article which resolves to /article. This is what the error says.
Though this works in development, it will give the said error in Prod build.
Add a value to the path and it should work!
paths: [{ params: { primary: 'abc', slug: [] } }],