My React/Redux portfolio project
Tags: react, javascript, api, rails
Published: 2019-04-15 18:26:10

---
title: My React/Redux portfolio project
published: true
description: A react app that I built for my school's final project assignment
tags: React, JavaScript, API, RubyonRails
---

![Trailista](https://i.imgur.com/fla25b0.jpg)
For my final project for Flatiron's online fullstack programming course, I built an app called ***[Trailista](https://github.com/kriti-rai/trailista)***, which pulls a list of trails from [Hiking Project Data API](https://www.hikingproject.com/data) by location. You can watch a short demo of my app [here](https://www.youtube.com/watch?v=Tq6YfMEufpQ&t=1s) or proceed to read as I briefly touch up on the setup and few roadblocks I came across during the process.

This app is definitely a WIP but so far here are the available featues:

* One can search for trails by city and country

  ![search](https://media.giphy.com/media/lrbwszQmty9ybUdBQs/giphy.gif)

* One can login or sign up

  ![registration](https://media.giphy.com/media/j0verhIyrSczORIdK0/giphy.gif)
		
* One can add trails to their favorites list and then delete them as they wish

     ![favorites](https://media.giphy.com/media/mDXrTRqf6EMfTAyNat/giphy.gif)
	 
## The way it works

* My app pulls trails from *Hiking Project API* endpoint that looks something like this

> www.hikingproject.com/data/get-trails?lat=40.0274&lon=-105.2519&maxDistance=10&key=APP_KEY

* The client supplies the values for *lat*, *lon* and *maxDistance* alongside a *key* that is provided by *Hiking Project*

* The app then takes the user inputs and plugs them into a `fetch` request, and sends it to *Hiking Project* API for a response back

Sounds pretty straightforward except that the user supplies the app with an address, e.g. a place's name, whereas *Hiking Project* API endpoint wants the address in the form of GPS coordinates, i.e. the lattitude and the longitude. So I had to find a way to convert the location input to GPS coordinates. After rummaging through *Hiking Project*' FAQs forum for some time, I  found a thread where someone had mentioned using *[MapBox](https://docs.mapbox.com/api/search/#geocoding)* to carry out, what they apparently call, "forward geo-coding", i.e. the process of converting an address to coordinates (the opposite would be *reverse geo-coding*). I also looked into [Google maps API](https://developers.google.com/places/web-service/intro) but apparently they charge? So, I decided to stick with MapBox.

And, boy was this fun? Yes, it involved some hair-pulling episodes but I'm fairly proud of this part the way I got it working. My two functions, the heroes of my app, `getCoordinates()` and `fetchHikes()`, work in coordination to make this happen. 


- `getCoordinates()`  takes the user input and sends a `fetch` request to *MapBox* API, like so:

```
getCoordinates= (e) => { 
    e.preventDefault();
    axios.get(`https://api.mapbox.com/geocoding/v5/mapbox.places/${this.state.city}.json?country=${this.state.countryCode}&access_token=APP_KEY`)
      .then(resp => {
        this.setState({
          longitude: resp.data.features[0].geometry.coordinates[0],
          latitude: resp.data.features[0].geometry.coordinates[1]
        })
				...
```

- The response data is then used to set the values of `longitude` and `latitude` in the state, which is then used to make a `fetch` request to *Hiking Project's* API via the dispatch action `fetchHikes()`

```
getCoordinates= (e) => {
...
   this.props.fetchHikes(this.state.latitude, this.state.longitude, this.state.maxDistance, this.state.maxResults)
  })
}
```

## The Set Up

This [article](https://www.fullstackreact.com/articles/how-to-get-create-react-app-to-work-with-your-rails-api/) does a great job of guiding one through setting up a React app with Rails API. I had a rough idea of what resources I will be working with so I started with my models and controllers first and then set up (API) routes (in *'/config/routes.rb'*) to which I could send `fetch` and/or `post` request. 

### Important!

One thing to look out for is your *CORS* (Cross Origin Resource Sharing) set up. Since my front-end and back-end were running on different domains, I had to find a way to tell my back-end server that the requests my front-end was sending were not harmful. If you initially set up your Rails API with the command `$ rails new myapp --api`, you get a `cors.rb` file already set up and you will just have to uncomment the following:

```
#Gemfile

gem 'rack-cors'

```

```
#app/config/initializers/cors.rb

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'localhost:3000'

    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

```

Once all this was taken care of, I then moved onto my *client* side, i.e. the front-end part. Also, before pulling data from *Hiking Project*, I created some seed data to test how the data is rendered on my front-end.

### Routes
I set up my routes in `App.js`. One interesting thing I found on the internet was that I could create a helper `PrivateRoute` to lock down a route if one is not logged in, like e.g. my '*/user*' route. This [article](https://reacttraining.com/react-router/web/example/auth-workflow) talks about how one can set up a `PrivateRoute`.

### Components

I started with presentational components that were mostly stateless and had DOM markups. As I progressed further I ended up adding props, state, connecting to the store and so on, which all led me to think about dividing up my components based on their functionality - containers and presentational. Containers are concerned with *how things work*, contain logic and the most of the times are stateful. The latter, on the other hand, are just "dumb" components that are concerned with *how things look* and has no logic or knowledge of state whatsoever. 

However, as Dan Abramov points out in this [article](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0), this pattern should not be enforced as a hard rule and if there is no necessity. So, you may see that some of my components act as both container and presentational or some of my presentational components have logic inside them and are not purely presentational. 

### Reducers

Speaking of separation of concerns, instead of having one giant reducer, I decided to have one reducer managing only one independent slice of the state.  So, I ended up with three reducers, `alertsReducer`, `hikesReducer` and `userReducer`. All of these reducing functions are then combined into a single reducer, `rootReducer`, using `combineReducers` helper function provided by `redux`. This reducer is what gets passed to `createStore`. 

# Conclusion

I had a lot of fun building this application. And, like with all other projects, this one came with frustration but I've learned that that's what makes the accomplishment at the end so much worthwhile. However, this is not over yet and I still want to keep working on the app, adding some  more features like comments, users being able to rate and create hikes and so on. For all I know, sky is the limit and there is always room for improvement. As of now, I'm happy that I'm ready for my final assessment. The journey has just begun!