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
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
}
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(', ')
}
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
})
}
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>
Top comments (0)