4

I'm starting with Next.js and after going through docs, I cannot figure out how to get the route param code inside getStaticPaths method as shown below!?. code is not known before hand by any means and it can be anything.

I don't want to call api and get the data using useEffect inside the component.

File: pages/post/[code].js

import React from 'react';
import apiCall from 'api/something';

export default ({post}) => {
     return <>
        render components here based on prop `post`
    </>
}

export async function getStaticPaths() {
    // How to get [code] from the route here, which can be used below?
    return { 
        paths: // NEED [code] HERE from current route,
        fallback: false
    }
} 

export async function getStaticProps(ctx) {
    return {
        props: { 
         // [ctx.code] resolved from current route with the help of getStaticPaths,
         post: apiCall(ctx.code) 
        }
    }
}

I've tried getServerSideProps which works for me:

export const getServerSideProps = async (ctx) => {
    return {
        props: {
            post: await apiCall(ctx.query.code)
        }
    };
};

But it fails when I do next export stating:

pages with getServerSideProps can not be exported. See more info here: https://err.sh/next.js/gssp-export

After investigating further on this error I found this solution, which is not feasible for me as my app is hosted on Heroku.

I'm trying to server-side render the html along with the data based on the route param code. But not able to do so now.

2
  • Are you not getting ctx.code in getStaticProps ?? Commented May 26, 2020 at 15:37
  • @pritesh I used getServerSideProps, which is failing on next export Commented May 27, 2020 at 7:32

2 Answers 2

7
+50

The purpose of the function getStaticPaths is to generate a list of paths for which static HTML will be rendered at build time. For example, for a list of 10 posts, you can generate 10 posts/[id] routes ahead of time if you know the id of the posts.

How getStaticPaths works with dynamic routes in more details..

Suppose you have a dynamic route /posts/[postId] if you choose to use static-generation you have to generate a list of paths that will include the postId as a route param and for each path returned, the function getStaticProps will be called to query the data at build time. Example,

// for /post/[postId]

export const getStaticPaths = async () => {
  // if you know all the postId ahead of time

  const paths = [
     { params: { postId: '1234' } },  // keep in mind postId has to be a string
     { params: { postId: '3792' } },
     { params: { postId: '1749' } },
  ]

  return {
    paths,
    fallback: false // we are disabling fallback because we know all the paths ahead of time
  }
}

// for each path returned getStaticProps will be called at build time
export const getStaticProps = async (context) => {
   // you have access to the postId params that you returns from
   // getStaticPaths here
   const postId = context.params.postId 

   // now you can query the data from postId and return as props

   return {
     props: // queried data
   }
}

If fallback is set to false any for any route path that is not returned from the function getStaticPaths nextjs will simply show a 404 error page.

How to use fallback: true to generate static pages for route params not known ahead of time

If you know some postId of the posts and the data for the posts do not change very often, you can choose to generate the pages with fallback property set to true, which will display a fallback version of the page for the paths that are not returned from the function getStaticPaths. And on request for the page nextjs will call getStaticProps and send the data as JSON which will be used to render the page in the browser. Example,

// for /post/[postId]
export const getStaticPaths = async () => {
   // you can get how many ever postIds are know ahead of time 
   // and return as paths with fallback set to true
   const posts = // queried data from db or fetched from remote API

   const paths = posts.map(post => { params:{ postId: post.id.toString() }})

   return {
      paths,
      fallback: true
   }

}

// in your page Component check for fallback and render a loading indicator
import { useRouter } from 'next/router';

const MyPage = (props) => {
  // before you do anything
  const router = useRouter();

  if (router.isFallback) {
    return <div>Loading....</div>
  }

  // rest of your page logic

}

If your data is very dynamic, let's say changing every 30mins or an hour or so. You can choose to use server-side rendering which will fetch the data on per request basis, but TTFB(time to first byte) will be higher. For example,

// for /post/[postId]
export const getServerSideProps = async (context) => {

  // you also have access to the param postId from the context
  const postId = context.params.postId

  // query the data based on the postId and return as props
  return {
    props: // queried data
  }  

}

Keep in mind if you choose to go with getServerSideProps the function will be called on per-request basis so time to first byte will be higher.

Depending on use-cases you can also use static generation with client-side data fetching using swr from nextjs team repo link.

Sign up to request clarification or add additional context in comments.

4 Comments

As mentioned in the question itself, I need to leverage getServerSideProps functionality, but it throws this error while exporting next app. Pls check my question again completely.
I get that you need next export and it's failing when using getServerSideProps. 'next export' will always fail when you export getServerSideProps from a page, because the function getServerSideProps needs a nodejs server to run. That's why i was suggesting that if you don't have incremental data requirements you can use getStaticPaths with fallback set to true instead. There could be another solution using getInitialProps and exportPathMap in your next.config.js which I think would not be a good solution.
Sincere thanks for the answer. A follow up question to this is : what if i have 3 articles in total with id => 1,2,3 For 2 of those articles, i need to use static generation. => for id 1,2 but for the remaining one article => id = 3 , i need to use server side rendering :) how can one do this.
For the comment i have posted , one needs to do fallback:blocking as mentioned in the docs.
0

As I understand, you want to statically generate dynamic routes at build time.

To do so you need to let Next.js know what pages to generate, by specifying all codes.

export async function getStaticPaths() {
    // you don't need here a code from current route
    // but you need to specify all known post codes
    return { 
        paths: [
          { params: { code: '1' } },
          { params: { code: '2' } },
          { params: { code: '3' } },
        ]
        fallback: false
    }
}

You would need to re-build app every time you change the posts.

Use getServerSideProps if you don't want to re-build project every time. Then the data would be fetched at request time. You can't export it because it requires Node.js server.

2 Comments

How can I implement Node.js server on top of Next.js, and make it export a SSR build?
@boop_the_snoot, You can run Next.js built-in server in Node.js environment - see nextjs.org/docs/deployment#nodejs-server. You can't export SSR build because Server Side Rendering requires a server.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.