Kaung Khant Zaw
Kaung Khant Zaw

Reputation: 1638

Usage of getStaticPaths with dynamic routes

I have an index page which I show movies by sections (trending movies, popular movies, etc.) and I am calling different api urls inside getStaticProps for that. Now in [movieId].js page, I am using getStaticPaths since I am using dynamic route. But what I don't understand is user can click on any movie item on any section but because of I need to get the paths for all the possible movies in [movideId].js page and return as paths in getStaticPaths,

How would I know which section a user has clicked so I can call that specific api in getStaticPaths to get the correct data and return the correct paths?

This is my codes

// index.js 

export default function Home(props) {

  return (
    <>
      <div>
        <h1>Trending</h1>
        {props.trending.results.map((movie, index) => {
          return (
            <div key={index}>
              <Link href={`/movie/${movie.id}`}>
                <a>{movie.original_title}</a>
              </Link>
            </div>
          );
        })}
      </div>

      <div>
        <h1>Popular</h1>
        {props.popular.results.map((movie, index) => {
          return (
            <div key={index}>
              <Link href={`/movie/${movie.id}`}>
                <a>{movie.original_title}</a>
              </Link>
            </div>
          );
        })}
      </div>
    </>
  );
}


export async function getStaticProps() {
  try {
    const token = '...';

    const [trendingRes, popularRes] = await Promise.all([
      fetch(
        `https://api.themoviedb.org/3/trending/movie/week?api_key=${token}`
      ),
      fetch(
        `https://api.themoviedb.org/3/movie/popular?api_key=${token}&language=en-US&page=1`
      )
    ]);

    const [trending, popular] = await Promise.all([
      trendingRes.json(),
      popularRes.json()
    ]);

    return { props: { trending, popular } };
  } catch (err) {
      return { notFound: true };
  }
}

// [movieId].js

export async function getStaticPaths() {

  const token = "...";
  const res = await fetch(
    `https://api.themoviedb.org/3/trending/movie/week?api_key=${token}` // here I am hardcoding to call trending api url no matter which section a user has clicked on 
  );
  const data = await res.json();

  return {
    paths: data.results.map((d) => ({ params: { movieId: d.id.toString() } }))
  };
}

Full Code sample

Now if a user clicks on a movie of popular section, it shows 404 not found page as I only have data and paths from trending api url.

I am still learning nextjs so hopefully my explanation is understandable, free free to ask more detail about this.

Upvotes: 1

Views: 4294

Answers (2)

moy2010
moy2010

Reputation: 902

Given your mentioned examples, I wouldn't use getStaticPaths but getServerSideProps, since the getStaticPaths use case is only for when you have a handful of pages that you want to generate statically.

Inside getServerSideProps you will have access to the context object. Then, accessing context.query will get you whatever the dynamic path of your page contains.

To give you an example:

In the pages folder of your Next.js project, create a folder called movies, and then create a [id].js inside of it.

This will match paths such as:

/movies/1
/movies/123
/movies/456

And then you can use the dynamic path (i.e. 123) to call your API and fetch the specific movie.

Upvotes: 1

Danila
Danila

Reputation: 18476

In real life if you have large data set you would not want to prerender all the possible combinations and all possible movie pages.

Luckily there is a fallback flag for getStaticPaths.

You can use fallback: blocking (docs), that way if the key of the page was not specified in getStaticPaths the page will be generated (and cached) after the first request. But you need an api where you can just fetch movie by id. You have it, so all you need to do is change fallback key. Check this Stackblitz example

If you don't have such an api you can for example split your routes and have /trending/[id] route and popular/[id] route. That way you would always know from where you need to fetch your movies.

Hope it makes sense, feel free to ask other questions.

Upvotes: 1

Related Questions