Project 82 of 100 - Rick Steves Tours App
Tags: react, javascript, 100daysofcode
Published: 2021-06-18 04:31:50

*Hey! I'm on a mission to make 100 React.js projects. Please follow my dev.to profile or my [twitter](https://www.twitter.com/jwhubert91) for updates and feel free to reach out if you have questions. Thanks for your support!*

Link to today's deployed app: [Link](https://determined-hopper-0ec6c1.netlify.app/)
Link to the repo: [github](https://github.com/jwhubert91/100daysofreact/tree/master/day-82-tours-app)

This was a fun little project and another from [this series from John Smilga](https://www.youtube.com/watch?v=a_7Z7C_JCyo). The styling is taken care of, we just need to hit the API and populate the tour components with the relevant data. The main new principle covered here is called *prop drilling* where we pass down props multiple levels from parent component to child to its child. We can pass down data or functions this way.

We hit the tour API at a static URL where there is a JSON array with tour objects of the following format:

```JS
{
"id": "rec6d6T3q5EBIdCfD",
"name": "Best of Paris in 7 Days Tour",
"info": "Paris is synonymous with the finest things that culture can offer — in art, fashion, food, literature, and ideas. On this tour, your Paris-savvy Rick Steves guide will immerse you in the very best of the City of Light: the masterpiece-packed Louvre and Orsay museums, resilient Notre-Dame Cathedral, exquisite Sainte-Chapelle, and extravagant Palace of Versailles. You'll also enjoy guided neighborhood walks through the city's historic heart as well as quieter moments to slow down and savor the city's intimate cafés, colorful markets, and joie de vivre. Join us for the Best of Paris in 7 Days!",
"image": "https://dl.airtable.com/.attachments/a0cd0702c443f31526267f38ea5314a1/2447eb7a/paris.jpg",
"price": "1,995"
},
```

Since hitting an API and populating data is pretty simple and I've covered this before many times, I won't go too deeply into it. As mentioned, the main new idea with this project was to create a function in a parent component and pass it down multiple levels to the child component where we have an onClick method on one of the component's buttons that calls the passed function and changes the state of the parent.

Specifically, since we make the API call in the `App` component and we have multiple `Tour` components, we store the data for all of those tours in the `App` component. But the Remove Tour button exists on each component, so in the `App` component we need to write a function that modifies state but pass it down to the `Tour` component.

Here is what the `App` component looks like with local state keeping track of tours and a function to modify it:

```JS
function App() {
  const [loading,setLoading] = useState(true)
  const [tours,setTours] = useState([])

  const removeTour = (id) => {
    const newTours = tours.filter((tour) => tour.id !== id)
    setTours(newTours)
  }
...
```

As you can see, the function modifies state. Now to pass it down multiple levels we can pass the function through props. Here we pass it to the `Tours` component:

```JS
...
  return <main>
    <Tours tours={tours} removeTour={removeTour} />
  </main>
```

And in the `Tours` component we also need to pass down the removeTour function from `App` which we do like so:

```JS
    <div>
      {tours.map((tour) => {
        return <Tour key={tour.id} {...tour} removeTour={removeTour}></Tour>
      }
      )}
    </div>
```

Now finally in the `Tour` component we place the function passed down through props in the onClick method on the Remove Tour button:

```JS
      <button className='delete-btn' onClick={() => removeTour(id)}>
        Not interested
      </button>
```

This will call the removeTour function passed all the way down from the App component on the ID, which is also passed down through props.

**If you like projects like this and want to stay up to date with more, check out my Twitter [@jwhubert91](https://twitter.com/jwhubert91), I follow back! See you tomorrow for another project.**