DEV Community

Cover image for React Fullstack Project for Flatiron
Chuck
Chuck

Posted on

React Fullstack Project for Flatiron

Introduction

Requirements

  • The code should be written in ES6 as much as possible
  • Use the create-react-app generator to start your project.
  • Your app should have one HTML page to render your react-redux application using 2 container components, 5 stateless components, and 3 routes.
  • The Application must make use of react-router and proper RESTful routing
  • Use Redux middleware to respond to and modify state change
  • Make use of async actions to send data to and receive data from a server
  • The Rails API should handle the data persistence and should be using fetch within your actions to GET and POST data from your API.
  • Your client-side application should handle the display of data with minimal data manipulation.
  • The application should have some minimal styling: feel free to stick to a framework (like react-bootstrap), but if you want to write (additional) CSS yourself, go for it!

App Design

React - As per the direction, I used Create React App to setup the frontend project.

SIDEBAR: I would rather have used my personal React boilerplate project using ParcelJS, but that may be a topic for another article.

FYI. This project is a redesign of a previous App for Flatiron utilizing Ruby on Rails only. You can read more about that project below.

Styling - Most projects I have spun put pretty quickly and have relied on Component UI's to decrease the development time. I have used Bootstrap, and TailwindCSS and Bulma. Even though my preference would be to employ SCSS, I did not need to be distracted with Styling for this project, I utilized Bootstrap with React-Bootstrap.

API - For accessing the data I used the MovieDB API, which is a well documented API and was a joy to work with. There is a level of complexity of the JSON data from the API, which at times was challenging.

Fetching API

As with the previous application, I used the RestClient gem to fetch the data, but because of the complexity of the JSON structure, I decided to seed the development DB:

movie_api = Rails.application.credentials.dig(:development, :movie_api)

n = 1
while n < 501
  movie_seed = JSON.parse(RestClient.get("https://api.themoviedb.org/3/movie/popular?api_key=#{movie_api}&page=#{n}"))
  movie_seed['results'].each do |movie|
    Movie.create(
      movie_id: movie['id'],
      title: movie['title'],
      release_date: movie['release_date'],
      poster_path: movie['poster_path'],
      backdrop_path: movie['backdrop_path'],
      overview: movie['overview'],
      average_vote: movie['vote_average'],
      popularity: movie['popularity'],
      budget: movie['budget'],
      tagline: movie['tagline'],
      runtime: movie['runtime'],
      genre_ids: movie['genre_ids']
    )
  end
  n += 1
end
Enter fullscreen mode Exit fullscreen mode

Movie Genres mapping

One problem with the retrieved JSON data from the Movie API, was the way movie genres were su0plied. In the original call, for each movie, an array is supplied of genre id's, but no genre names. I stored these id's in an array in the Postgres DB.

I made a second call to the Movie API using curl and saved the genre table, mapping id's to strings, to a JSON file which I converted to a JavaScript object to read from:

let genres = [
  {
    id: '28',
    name: 'Action'
  },
  {
    id: '12',
    name: 'Adventure'
  },
  {
    id: '16',
    name: 'Animation'
  },
  {
    id: '35',
    name: 'Comedy'
  },
  {
    id: '80',
    name: 'Crime'
  },
  {
    id: '99',
    name: 'Documentary'
  },
  {
    id: '18',
    name: 'Drama'
  },
  {
    id: '10751',
    name: 'Family'
  },
  {
    id: '14',
    name: 'Fantasy'
  },
  {
    id: '36',
    name: 'History'
  },
  {
    id: '27',
    name: 'Horror'
  },
  {
    id: '10402',
    name: 'Music'
  },
  {
    id: '9648',
    name: 'Mystery'
  },
  {
    id: '10749',
    name: 'Romance'
  },
  {
    id: '878',
    name: 'Science Fiction'
  },
  {
    id: '10770',
    name: 'TV Movie'
  },
  {
    id: '53',
    name: 'Thriller'
  },
  {
    id: '10752',
    name: 'War'
  },
  {
    id: '37',
    name: 'Western'
  }
]

module.exports = {
  genres
}
Enter fullscreen mode Exit fullscreen mode

Then I was able to map over the supplied id's, compare them to the saved data from a local file called movieGenres.js. In the MovieCard component I needed a string to display the genres, so the following accomplished the goal:

const MovieCard = ({ id, title, genre_ids, poster_path, average_vote }) => {
  let idStr = id.toString(8)
  let genresStr = ''
  if (genre_ids) {
    genresStr = genre_ids
      .map(id => {
        const item = genreMap.genres.find(item => item.id === id)
        return item ? item.name : null
      })
      .join(', ')
  }
Enter fullscreen mode Exit fullscreen mode

In the Movie Detail component, I needed an array to map over to show a listing of genres' using a Bootstrap Badge:

let genresArr = []
  if (genre_ids) {
    genresArr = genre_ids.map(gid => {
      const item = genreMap.genres.find(item => item.id === gid)
      genresArr.push(item.name)
      return genresArr
    })
  }

Enter fullscreen mode Exit fullscreen mode

Then displaying the Badges:

<div>
  <span className="mr-2">Genres:</span>
    {genresArr[0].map(item => (
      <Badge variant="warning" className="mb-1" key={item}>
        {item}
      </Badge>
    ))}
</div>
Enter fullscreen mode Exit fullscreen mode

Latest comments (0)