I want to start with creating the list of houses view.

We’ll implement that in the homepage of the project, which is defined by the pages/index.js file we created in the last lesson.

Now let’s take a look at the Airbnb stays listing:

I’d like to create something similar. Not pixel perfect, of course. I just want to implement similar functionality, but since I’m not a designer, I’m also going to borrow some of the style used here. We’ll adhere to that as much as possible without going too crazy about that.

The first thing we’re going to do is, we are going to define 2 houses. We’ll do that in a JavaScript file which I’m going to call houses.json, in the pages folder (create it).

Inside this file, we’ll define a houses array with 2 entries, which contain data I got from the Airbnb homepage I opened in my browser. You can add any data you want, of course. I copied the default picture of 2 houses and stored them in the public/img/houses/ folder (create it in your project), with some details about the houses, which we’ll use to build the houses list:

pages/houses.json

[
  {
    "picture": "/img/houses/1.jpg",
    "type": "Entire house",
    "town": "Ostuni",
    "title": "Beautiful flat in Ostuni!",
    "rating": 4.93,
    "reviewsCount": 198
  },
  {
    "picture": "/img/houses/2.jpg",
    "type": "Entire house",
    "town": "Isla Mujeres",
    "title": "The World Famous Seashell House ~ Casa Caracol",
    "rating": 4.77,
    "reviewsCount": 246
  }
]

Files in the public folder are automatically served statically by Next.js. You can immediately see the house image by opening your browser at http://localhost:3000/img/houses/1.jpg

Later on, we’ll extract houses from the database instead of this JSON file, but for the time being let’s stick to this static catalog.

Let’s switch back to our pages/index.js file.

Now we can import this JSON into our page component using the syntax

pages/index.js

import houses from './houses.json'

Now we can iterate over those houses in our component JSX, wrapping all of them in a div with class houses:

pages/index.js

import houses from './houses.json'

const Index = () => (
  <div>
    <h2>Places to stay</h2>

    <div className='houses'>
      {houses.map((house, index) => {
        //...
      })}
    </div>
  </div>
)

export default Index

See https://flaviocopes.com/react-how-to-loop/

Let’s now create a separate component to render the single house in the list.

We’ll name it House, and we’ll store it in a file named House.js in new components folder in the project root.

Let’s create this file and just return a basic “House” text from it:

components/House.js

const House = () => (
  <div>
    <h2>House</h2>
  </div>
)

export default House

That is an implicit return, a feature of arrow functions. Look for “implicit return” on https://flaviocopes.com/javascript-arrow-functions/

In pages/index.js we can now import it:

pages/index.js

import House from '../components/House'

and we can use it inside the JSX to render it for every house in the houses array:

pages/index.js

{houses.map((house, index) => {
  return <House key={index} {...house} />
})}

We pass all the house properties as props using the {...house} syntax.

See https://flaviocopes.com/react-props/

We also add a key inside the list, because React wants that.

This is what you should see now in the browser:

Now open the components/House.js file and accept the props argument, then log its content before returning the JSX:

components/House.js

const House = props => {
  console.log(props)
  return (
    <div>
      <h2>House</h2>
    </div>
  )
}

export default House

If you open the browser console, you should see this:

Props logged

Now that we have those props coming in, we can render them in the output of the component:

components/House.js

const House = props => {
  return (
    <div>
      <img src={props.picture} width='100%' alt='House picture' />
      <p>
        {props.type} - {props.town}
      </p>
      <p>{props.title}</p>
      <p>
        {props.rating} ({props.reviewsCount})
      </p>
    </div>
  )
}

export default House

Now the home page of the site should look similar to this:

Houses list

Note that the images I used are copyrighted and I will not include them in the project source code, but you can add any image in public/img/houses/1.jpg and public/img/houses/2.jpg to suit the sample code. Create the public/img/ as it does not exist by default.

Using Next.js we have the ability to use styled-jsx in our components, to add scoped CSS (CSS that is applied only to the component it’s added to, and does not leak outside):

Let’s use CSS Grid to style this list a little bit better. In pages/index.js, add the following block inside the JSX:

pages/index.js

<style jsx>{`
  .houses {
    display: grid;
    grid-template-columns: 50% 50%;
    grid-template-rows: 300px 300px;
    grid-gap: 40px;
  }
`}</style>

Like this:

pages/index.js

import houses from './houses.json'
import House from '../components/House'

const Index = () => (
  <div>
    <h2>Places to stay</h2>

    <div className='houses'>
      {houses.map((house, index) => {
        return <House key={index} {...house} />
      })}
    </div>

    <style jsx>{`
      .houses {
        display: grid;
        grid-template-columns: 50% 50%;
        grid-template-rows: 300px 300px;
        grid-gap: 40px;
      }
    `}</style>
  </div>
)

export default Index

This should be the result of all our work in this module:

End result

The code for this lesson is available at https://github.com/flaviocopes/airbnb-clone-react-nextjs/commit/747599bfd139c5910ef0ac2f4533a1a11778dd1b


Go to the next lesson