38

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

3 Answers 3

61
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> ); } 
Sign up to request clarification or add additional context in comments.

5 Comments

in case it helps anyone, this response is completely incorrect - though it could just be outdated. In 2020 next's getServerSideProps requires you to return an object containing the keyword props for your props to go into the component it is exported alongside.
well I'm not entirely sure what you say is true, I've based my statement on (a) what is explicitly stated in the next js documentation, and (b) a working piece of my own code....
the title refers to getServerSideProps ... the OP is for getServerSideProps ... your own answer is for getServerSideProps ... my comment was about getServerSideProps ... so why are you now talking about getInitialProps ??!!
(though I would also say its a shame they are inconsistent given they are both providing very similar functions within the same framework, but it was probably something to do with backwards compatibility)
One point I like to bring up here for the Next,js 13 update is that, I doubt if there is a replacement for getServerSideProps. The document here suggests to use fetch which is a client side http call, rather than the direct method call in the server. Having said that the const { id } = context.query; line worked perfectly fine when having params in the url like say http://..../fruit?id=1433 or similar
3

There's nothing wrong in how you're handling the dynamic routing of the page. The issue is that the data returned by the API is an array but your code expects it to be an object. You can retrieve the first item from the array and pass that to the component from getServerSideProps.

export async function getServerSideProps(context) { const { id } = context.params; // Use `context.params` to get dynamic params const res = await fetch(`https://restcountries.com/v2/name/${id}`); // Using `restcountries.com` as `restcountries.eu` is no longer accessible const countryList = await res.json(); const [country] = countryList; // Get first item in array returned from API return { props: { country } }; } const Country = ({ country }) => { console.log(country); return ( <> <h1>{country.name}</h1> <span>{country.capital}</span> </> ); }; export default Country; 

Comments

1

Just to add to the accepted answer, you could also destructure to make it (imho) more readable. This is entirely optional though

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.