Search code examples
javascriptreactjsnext.jsserver-side-renderingdynamic-url

Dynamic routing with getServerSideProps in Nextjs


I'm trying to learn nextjs. Struggling to work out routing with getServerSideProps.

Using a free API I have a list of countries displayed on the DOM. I want to dynamically link to a country and data be fetched and displayed for that specific country.

Heres my code so far

const Country = props => (
  <Layout>
    <h1>{props.country.name}</h1>
    <span>{props.country.capital}</span>
  </Layout>
);
export async function getServerSideProps(context) {
  const { id } = context.query;
  const res = await fetch(`https://restcountries.eu/rest/v2/name/${id}`);
  const country = await res.json();

  console.log(`Fetched place: ${country.name}`);
  return { props: { country } };
}
export default Country;

  <div className='container'>
    <Head>
      <title>Countries List</title>
      <link rel='icon' href='/favicon.ico' />
    </Head>
    <Layout>
      <main>
        <h1>
          Countries{' '}
          <span role='img' aria-label='world emoji'>
            🌎
          </span>
        </h1>
        <ul>
          {countries.map(country => (
            <li key={country.name}>
              <Link href='/p/[id]' as={`/p/${country.name}`}>
                <a>{country.name}</a>
              </Link>
            </li>
          ))}
        </ul>
      </main>
    </Layout>
  </div>
);

export async function getServerSideProps() {
  // Call an external API endpoint to get posts.
  const res = await fetch('https://restcountries.eu/rest/v2/all');
  const countries = await res.json();

  // By returning { props: posts }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      countries,
    },
  };
}

export default Home;

The URL dynamically routes ok. For example, when you click on Afghanistan the URL shows http://localhost:3000/p/Afghanistan.

My country component however doesn't display anything and undefined is printed to the terminal.

Example of URL and response from URL: https://restcountries.eu/rest/v2/name/Afghanistan

{
name: "Afghanistan"
}

Apologies if a noob question. Trying to learn nextjs


Solution

  • export async function getServerSideProps(context) {
      const { id } = context.query;
      const res = await fetch(`https://restcountries.eu/rest/v2/name/${id}`);
      const country = await res.json();
    
      console.log(`Fetched place: ${country.name}`);
      return { props: { country } };
    }
    

    you are returning a nested object from above function

        { props: { country:country } }
    

    so this prop will be attached to props as like this:

          `props.props`
    

    this is how you should implement

    const Country = props => (
      <Layout>
        <h1>{props.props.country.name}</h1>
        <span>{props.props.country.capital}</span>
      </Layout>
    );
    

    UPDATE

    In early version of next.js I think updated after version 9, we were not returning from serverside function by using props. As of now correct way of implementation is

    return {
        props: {
          countries,
        },
      };
    

    Next.js 13 Update

    In next.js 13, if you set app directory, components in this directory will be server-rendered components by default. That means everything will be run on the server and we do not need to write specifiacallygetServerSideProps. in "app" directory, if your file name is surrounded by [..id], it means it is a dynamic route. In page.jsx, you can access id like this

    enter image description here

    export default function ProductPage({ params }) {
      return (
        <div>
          <h1>Product ID: {params.id}</h1>
        </div>
      );
    }