This content originally appeared on flaviocopes.com and was authored by flaviocopes.com
This post is part of a new series where we build a clone of Airbnb with Next.js. See the first post here.
- Part 1: Let’s start by installing Next.js
- Part 2: Build the list of houses
In the previous lesson we generated a list of houses.
In this lesson the goal is to make each of them clickable, and once clicked, we’ll transition the page to a new URL, which contains the ID of the house, and the site should show us a detail view.
The list will disappear and instead we’ll get more details about the house we selected.
First, I’m going to assign an id
number to each house in the houses.js
file:
houses.js
export default [
{
id: 1,
picture: '/img/1.jpg',
type: 'Entire house',
town: 'New York',
title: 'Beautiful flat in New York!'
},
{
id: 2,
picture: '/img/2.jpg',
type: 'Entire house',
town: 'Amsterdam',
title: 'A flat in Amsterdam with a great view'
}
]
Then we’ll use this id
to build a unique URL to each house, like /house/1
and /house/2
.
Let’s add a link to a house from the components/House.js
component, which now has this content:
components/House.js
export default function House(props) {
return (
<div>
<img src={props.picture} width="100%" alt="House picture" />
<p>
{props.type} - {props.town}
</p>
<p>{props.title}</p>
</div>
)
}
Normally, to add a link we’d use the HTML a
tag.
Not in Next.js.
Well, we could use the a
tag, but then client-side navigation will not work, and instead we’ll get the normal full page reload when nagivating across different pages. Next.js is great because a site using it will have that immediate feel, that fast feel that we can get using client side rendering.
Let’s import the Link component, the one that can help us with this problem.
components/House.js
import Link from 'next/link'
Then to link to a house, we wrap all inside an a
tag, and we wrap this tag inside a Link
tag, which will come with 2 attributes, href
and as
, which determine the page component that will be used and the URL:
components/House.js
import Link from 'next/link'
export default function House(props) {
return (
<Link href="/houses/[id]" as={'/houses/' + props.id}>
<a>
<img src={props.picture} width="100%" alt="House picture" />
<p>
{props.type} - {props.town}
</p>
<p>{props.title}</p>
</a>
</Link>
)
}
Now houses in the list are a link to the detail page.
Clicking the link won’t get us anywhere right now. We still need to build that detail page URL.
Now, let’s add more information to each house. We’re going to have a detail view, and this detail view will display more information. I am only going to update the first house (we’ll test our interface with that), and we’ll use the second to make sure the house page renders nicely even if we don’t have all the information.
I am going to add the following fields:
description
contains an HTML string to render as the house description, which now is just a placeholderguests
the number of guests the house can host
houses.js
export default [
{
id: 1,
picture: '/img/1.jpg',
type: 'Entire house',
town: 'New York',
title: 'Beautiful flat in New York!',
description:
'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur',
guests: 4
},
{
id: 2,
picture: '/img/2.jpg',
type: 'Entire house',
town: 'Amsterdam',
title: 'A flat in Amsterdam with a great view',
description:
'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur',
guests: 4
}
]
Let’s now create the template for the single house. We’re going to do so in a file pages/houses/[id].js
. The name is a bit weird, right? But there’s a reason. Next.js will use it any time the URL point to that /houses
path, and has a path that points to an ID, like /houses/2
.
Create the pages/houses/[id].js
file with this content:
pages/houses/[id].js
export default function House() {
return (
<div>
<p>Test</p>
</div>
)
}
Then manually point your browser to open that /houses/2
URL:
If the number in the URL changes, like /houses/1
, it does not matter - the same component will render, but with different data. This is called a dynamic page.
Now we must add a function in this file, called getServerSideProps
.
The job of this function is to retrieve the house id
from the URL, and look it up in the data (our JSON file, at the moment), and return it.
Everything returned from this function will be available as part of the component props.
Let’s start by defining it:
pages/houses/[id].js
export async function getServerSideProps() {}
This function gets a context
object which has the query
property. We just need this at the moment, so we can use object destructuring to retrieve it in the parameters:
pages/houses/[id].js
export async function getServerSideProps({ query }) {
console.log(query)
}
If you open the browser now, you’ll see an error - Next.js expects this to return an object with a props
property, so let’s return it:
pages/houses/[id].js
export async function getServerSideProps({ query }) {
console.log(query)
return { props: {} }
}
The terminal will now list the id
you called the page with, for example { id: '2329' }
if the page URL was http://localhost:3000/houses/2329
.
Now let’s get the id
value, and we can use it to filter the house from the JSON file that holds all the houses data:
pages/houses/[id].js
import houses from '../../houses.js'
//
export async function getServerSideProps({ query }) {
const { id } = query
return {
props: {
house: houses.filter((house) => house.id === parseInt(id))[0]
}
}
}
Great! Now we can reference the house
object in the component props:
pages/houses/[id].js
import houses from '../../houses.js'
export default function House(props) {
return (
<div>
<p>{props.house.title}</p>
</div>
)
}
export async function getServerSideProps({ query }) {
const { id } = query
return {
props: {
house: houses.filter((house) => house.id === parseInt(id))[0]
}
}
}
Now we can write the exact same template we used in the list, previously, except every field is now prepended with house.
:
pages/houses/[id].js
import houses from '../houses.js'
const House = (props) => (
<div>
<img src={props.house.picture} width="100%" alt="House picture" />
<p>
{props.house.type} - {props.house.town}
</p>
<p>{props.house.title}</p>
</div>
)
House.getInitialProps = ({ query }) => {
const { id } = query
return {
house: houses.filter((house) => house.id === id)[0]
}
}
export default House
Here’s the result so far:
Make sure you hit a URL that points to one of the id
we added in the JSON, like http://localhost:3000/houses/2
.
You can go to the homepage and then click one of the houses, then click the back button (or the Home link) and click another house, you’ll see both the URL and the page content change.
The thing I want to do now is: improve the template.
First, we’re going to use the house title as the title of the page.
We import the Head
component from next/head
:
pages/houses/[id].js
import Head from 'next/head'
then inside the component JSX we can include this component with a title
tag inside, which will add it to the page head
section during rendering:
pages/houses/[id].js
import Head from 'next/head'
import houses from '../../houses.js'
export default function House(props) {
return (
<div>
<Head>
<title>{props.house.title}</title>
</Head>
<img src={props.house.picture} width="100%" alt="House picture" />
<p>
{props.house.type} - {props.house.town}
</p>
<p>{props.house.title}</p>
</div>
)
}
export async function getServerSideProps({ query }) {
const { id } = query
return {
props: {
house: houses.filter((house) => house.id === parseInt(id))[0]
}
}
}
This is the result:
Awesome!
This content originally appeared on flaviocopes.com and was authored by flaviocopes.com

flaviocopes.com | Sciencx (2021-12-03T05:00:00+00:00) Airbnb clone, build the house detail view. Retrieved from https://www.scien.cx/2021/12/03/airbnb-clone-build-the-house-detail-view/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.