NextJS: How do I get exportPathMap page data? I don't see it in getStaticProps - reactjs

I have set up exportPathMap but I get an empty object when exporting getStaticProps from my component. I don't understand how I'm supposed to access it?
// next.config.js
exportPathMap: async function (
defaultMapPath,
{ dev, dir, outDir, distDir, buildId }
) {
const paths = {}
const response = await fetch(...)
const data = await response.json()
data.forEach((item) => {
paths[`/item/${item.id}`] = {
page: '/itemPage',
query: {
item,
},
}
})
return paths
},
And
// itemPage.js
...
export async function getStaticProps(props) {
console.log('props', props) // returns "props {}""
return {
props: props
}
}
...

It's difficult to find it specifically stated in the documentation right now, but here are your options.
OPTION 1
Use getStaticPaths and getStaticProps like so (from "with-static-export" in the nextJS examples)
// [id].js post file
export async function getStaticPaths() {
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts?_page=1'
)
const postList = await response.json()
return {
paths: postList.map(post => {
return {
params: {
id: `${post.id}`,
},
}
}),
fallback: false,
}
}
export async function getStaticProps({ params }) {
// fetch single post detail
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts/${params.id}`
)
const post = await response.json()
return {
props: post,
}
}
OPTION 2
Use exportPathMap AND getInitialProps
// item.js
...
Page.getInitialProps = function (context) {
return context.query.item
}
// next.config.js
module.exports = {
// ...Same as in your question...
}
Both will allow you to have static optimization. With Option 1, you need not export, next build is sufficient. For Option 2 you will need to run next export
From: https://nextjs.org/docs/advanced-features/static-html-export
If your pages don't have getInitialProps you may not need next export at all; next build is already enough thanks to Automatic Static Optimization.
Another note: You can use both methods inside a single project.

Related

getStaticProps runs on every request in production

I use Next JS in my project. I want do only one request in page. And in next docs says that using get Static Props is that's what I need. But in doesnt work for me.
This is my code
export async function getStaticPaths() {
const leaguesCol = await collection(database, 'leagues');
const leaguesSnapshot = await getDocs(leaguesCol);
const leagues = leaguesSnapshot.docs.map(doc => doc.data());
return {
paths: leagues.map((item) => ({
params: {
id: item.link,
},
})),
fallback: false,
};
}
export async function getStaticProps() {
const { id } = context.params;
const leaguesRef = await collection(database, 'highlights');
const q = query(leaguesRef, where('league', '==', id));
const leagueSnapshot = await getDocs(q);
const data = leagueSnapshot.docs.map(doc => doc.data());
return {
props: { data },
};
}
But, when i deploy project in Firebase, i see that request happens in every routing to page. For example, in screen my routing between "spain" and "germany" pages
enter image description here

Fetch wont work in getStaticProps for ISR but works for CSR

I'm trying to fetch some data using the -
import { useBhagwadGitaQuote, useTime } from '../api/Endpoints';
...
...
(default export component code)
...
...
export async function getStaticProps() {
const { timeData } = await useTime();
console.log(timeData);
return {
props: {
timeData
},
revalidate: 86400,
};
}
The useTime is defined as -
export const useTime = async () => {
const options = {
method: 'GET',
};
const link = 'https://worldtimeapi.org/api/timezone/Asia/Kolkata';
const raw = await fetch(link, options);
const timeData = await raw.json();
console.log(timeData);
return { timeData, isLoading: !timeData };
};
When I run it with yarn run dev it does not works and throws this error -
However, it works fine with Client Side Rendering, When I call the Hook useTime, inside the functional component, at the client's end.

How to generate the list of route segment parameters for every pokemon using generateStaticParams in Next.js 13?

I am trying to use Nextjs 13's generateStaticParams to render static data into my web page. How do I generate the list of routes like /pokemon/[pokemonName] for every pokemon name using the generateStaticParams without providing hard-coded pokemon name (for example here I put "charmander" as argument for fetchData and then it generate route just for charmander)?
export const generateStaticParams = async (): Promise<PageParams[]> => {
const res = await fetchData("charmander");
return [
{
pokemonName: res?.data.pokemon.name,
},
];
};
Fetching pokemon moves from graphQL-pokeAPI:
const fetchData = async (pokemonName: string) => {
const POKEMON_MOVES = `
query pokemon($name: String!) {
pokemon(name: $name) {
id
name
sprites {
front_default
}
moves {
move {
name
}
}
}
}
`;
const res = await fetch("https://graphql-pokeapi.graphcdn.app/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: POKEMON_MOVES,
variables: { name: pokemonName },
}),
});
const moves = await res.json();
return moves;
};
export default function SpecificPokemon({ params }) {
const { pokemonName } = params;
const pokemonData = use(fetchData(pokemonName));
return (<h1>{pokemonName}</h1>...)
};
In the Nextjs13 beta docs, it said that generateStaticParams doesn't require any context parameters. So I can't pass pokemonName into generateStaticParams like this, right?
export const generateStaticParams = async (pokemonName: string) => {
const res = await fetchData(pokemonName);
I tried to just write fetchData("") and the page just blank. Also, it would be too many to write like this:
return [
{ pokemonName: "bulbasaur" },
{ pokemonName: "ivysaur" },
{ pokemonName: "venusaur" },
];
Also, is this due to my lack of JS / Next13 concept understanding?
They actually have a feature called getStaticPaths which was specifically designed for this. You can easily make a call to a pokemon api and parse the response into getStaticPaths at run to generate the static paths you want to use. I encourage you to play with the documentation more, that team did a killer job with them.
export async function generateStaticParams() {
const posts = await getPosts();
return posts.map((post) => ({
slug: post.slug,
})
);
}
Here's an example for a posts table - but basically you get all the posts or in your case Pokemon, and map the names to an array.
I'm not sure if there's a better way of handling it but that should point you in the right direction. I'm still reading up on NextJS and especially the new Beta myself, so take with a pinch of salt.

Next.js keeps generating 404 page instead of blog details page

I am trying to generate my blog details page but next keeps giving me the 404 page. I am fetching the data from a headless cms called contentful. Here is what my file structure and code looks like
And this is my [path]s.js page
import {createClient} from "contentful"
const client = createClient({
space: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
accessToken: "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
});
export const getStaticPaths = async () => {
const res = await client.getEntries({
content_type: "blog"
})
const paths = res.items.map(item => {
return {
params: {slug: item.fields.slug}
}
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async ({params}) => {
const {items} = await client.getEntries({
content_type: "blog",
"fields.slug": params.slug
})
return {
props: {blog: items[0]}
}
}
function blogDetails({blog}) {
console.log(blog)
return (
<div>
Blog details
</div>
)
}
export default blogDetails
I do not understand where I am going wrong. What could be my problem?.
Firstly, you cannot use the square brackets as a "wildcard" at the beginning of the path and add some other characters after. So you should rename your file as just [path].js (without the s after [path]).
Secondly, in your getStaticPaths function, when you return the object of params inside paths, name the keys as the dynamic path you've named your file as. In your case, the object you return should be params: {path: item.fields.slug}. Alternatively, you can rename your file as [slug].js and leave the code like it is.
// [path].js
export const getStaticPaths = async () => {
const res = await client.getEntries({
content_type: "blog"
})
const paths = res.items.map(item => {
return {
params: {path: item.fields.slug} //renamed the key as "path"
}
})
return {
paths,
fallback: false
}
}
You can read more about dynamic routes and getStaticPaths() in the official documentation.

How can I ensure that the Next.js router.query is not undefined?

I'm using next.js and the import { useRouter } from 'next/router'.
However on initial load, router.query.id is undefined. It quickly fills in, but that initial load is a killer.
I'm trying to figure out how to do it, and tried:
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
// const res = await fetch(`https://.../posts/${params.id}`)
// const post = await res.json()
console.log(params)
// Pass post data to the page via props
return { props: { params } }
}
but this returns an error:
Error: getStaticPaths is required for dynamic SSG pages and is missing for '/app/d/[id]'.
I can't use getStaticPaths, since [id] is variable and can be any number of things.
So what's the best way to handle this?
I would do smt like this(without staticProps):
function Page(props) {
const router = useRouter();
const { query = {} } = router || {};
const { id = 0 } = query || {};
useEffect(()=> {
if(id) {
(async ()=> {
const res = await fetch(`https://.../posts/${id}`)
const post = await res.json();
})();
}
}, [id]);
}
And this is what official doc. says:
// You also have to define a Post component in the same file (pages/posts/[id].js)
function Post({ post }) {
const router = useRouter()
// If the page is not yet generated, this will be displayed
// initially until getStaticProps() finishes running
if (router.isFallback) {
return <div>Loading...</div>
}
return <h1>Posts are here</h1>;
}
// This also gets called at build time
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// Pass post data to the page via props
return { props: { post } }
}
UPDATE:
After a bit research, have figure out this solution with staticProps:
export default function Post({ post }) {
return <h1>Post is here</h1>;
}
export async function getStaticPaths() {
return {
paths: [
{ params: { id: '*' } }
],
fallback: true
};
}
export async function getStaticProps(context) {
const res = await fetch(`https://api.icndb.com/jokes/random/${context.params.id}`);
const post = await res.json()
return { props: { post } }
}

Resources