Movie App with React

Movie App with React

·

10 min read

I began learning react.js a few weeks ago and it has been quite an experience. So, I decided to practice by building a movie website. This article shows how I built a movie app using react-router. Come along with me, sit tight, and enjoy the ride.

what to do?

  1. Create your app by running npx create-react-app my-movie-app And then cd into the created folder. Good.
  2. Install react-router by running the command
    npm install react-router-dom
    
    for the purpose of this tutorial, we would also be installing bootstrap and axios. Therefore, we run
    npm install axios --save
    
    npm install bootstrap  --save
    
    Now that that's done we can run npm start. Cool.

our movie app is going to have 3 components, a Movie component, a MovieDisplay component, which displays the generated movies and a MovieDetails component which gives us information about a particular movie.

In our app.js we link the Movie and the aboutMovie components by placing them in a <Route> tag and wrapping them inside the <BrowserRouter> tag like so.

import React from 'react';
import './index.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import Movies from './components/Movies';
import MovieDetails from './components/MovieDetails';

function  App () {

  return (
    <div className='main'>
    <BrowserRouter>
         <Route path='/' exact component={Movies} />
        <Route path='/MovieDetails/:id' component={MovieDetails} />
    </BrowserRouter>
</div>
  );
}

export default App;

The <Route> tags are links between the components and we specify which component to load by using the path attribute. Notice also that we added exact to the first <Route> tag, this tells the browser to only return the exact match of the route.

In a file called axios.js we create our baseUrl for our Api thus

import axios from "axios";

export default axios.create({
    baseURL: 'https://yts.mx/',
});

let's style our pages so they look good, in index.css add the following styles (you can choose to use your own styles)

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Montserrat', sans-serif;
}

body {
  background-color: #19181F;
}

.movies {
  max-width: 1440px;
  margin: 40px auto;
  border-radius: 4px;
  padding: 32px;
}

.movies img {
  -o-object-fit: cover;
     object-fit: cover;
  -webkit-box-shadow: 0px 4px 24px 3px rgba(92, 163, 163, 0.43);
          box-shadow: 0px 4px 24px 3px rgba(92, 163, 163, 0.43);
  border-radius: 10px;
}

.movies img:hover {
  -webkit-transform: scale(1.1);
          transform: scale(1.1);
  -webkit-transition: .3s;
  transition: .3s;
}

.movies__title {
  margin-top: 15px;
  color: #FFFFFF;
  margin-left: 5px;
  padding-top: 5px;
  font-weight: 700;
  font-size: 20px;
}

.movies__year {
  color: #FFFFFF;
  margin-left: 5px;
  font-weight: 300;
  font-size: 20px;
}

.movies button {
  margin: 20px auto;
  background-color: #cebfbf;
  padding: 5px 20px 5px 20px;
  border-radius: 5px;
  font-size: 300;
  border-radius: 6px;
}

.movie-details {
  max-width: 1440px;
  margin: 40px auto;
  padding: 32px;
}

.movie-details img {
  -o-object-fit: cover;
     object-fit: cover;
  -webkit-box-shadow: 0px 4px 24px 3px rgba(0, 0, 0, 0.43);
          box-shadow: 0px 4px 24px 3px rgba(0, 0, 0, 0.43);
  border-radius: 10px;
}

.movie-details__all {
  padding-top: 80px;
  color: #fff;
}

.movie-details__all__title {
  font-weight: 700;
  font-size: 40px;
  line-height: 59px;
}

.movie-details__all__year {
  font-weight: 300;
  font-size: 27px;
  line-height: 37px;
}

.movie-details__all__genre {
  font-weight: 300;
  font-size: 27px;
  line-height: 37px;
  margin-bottom: 30px;
}

.movie-details__all__description {
  font-size: 24px;
  line-height: 29px;
}

.movie-details button {
  margin: 20px;
  background-color: #cebfbf;
  padding: 10px 22px 10px 22px;
  border-radius: 5px;
}

now that our pages look good we can continue.

In our Movie component, we call the API to return some data(movies) which will be displayed on the MovieDisplay component.

import React, {useState, useEffect} from 'react';
import yts from 'axios'
import 'bootstrap/dist/css/bootstrap.min.css';
import MovieDisplay from './MovieDisplay';

  const myData = (data) => {
    return {
        error: false,
        data,
    };
  };

const fetchMovie = async (page, limit) => {
  try {
      let { data: res } = await yts.get(`https://yts.mx/api/v2/list_movies.json/?quality=3D`, {
          params: {
              page,
              limit,
          },
      });
      return myData(res.data.movies);
  } catch (err) {
      return ({
          message: 'Opps! Something went wrong while fetching the data',
      });
  }
};

const  Movies = () => {

    const limit = 12;
    const [movies, setMovies] = useState([]);
    const [currentPage, setCurrentPage] = useState(1);

    useEffect(() => {
        (async () => {
            const { data} = await fetchMovie(currentPage, limit);

            setMovies((movies) => [...movies, ...data]);
        })();
    }, [currentPage]);

  return (
        <div className= "movies row pt-5">
        {movies.map((movie) => {
                        return <MovieDisplay key={movie.id} movie={movie} />;
                    })}      
                    <button  onClick={() => setCurrentPage(currentPage + 1)}>
                         Show more movies...
                     </button>
        </div >
  );
}

export default Movies;

We also created a button that on click loads another page with more movies. Pretty cool right?.

In MovieDisplay.js

import React from 'react';
import { Link } from 'react-router-dom';

const MovieDisplay = ({ movie }) => {

    return (
        <div className= "col-md-3">  
                <Link to={`/MovieDetails/${movie.id}`}>
                    <img className="img-fluid" src={movie.medium_cover_image}  alt={movie.title_long}  />
                </Link>
                <h3 className='movies__title'>{movie.title}</h3>
                <p className="movies__year">{movie.year}</p>
            </div>
    )
}

export default MovieDisplay;

Here have an <img> tag which generates images from the API. the image tag is enclosed in a <link> tag which is linked to the id of the movie such that when an image is clicked on it gives us the details of that particular movie.

Finally, in `MovieDetails.js we fetch the movie details from the API and display the details we need on the page such as the title, genre, and movie description.

import React, { useState, useEffect} from 'react';
import yts from '../axios';
import { Link } from 'react-router-dom';

const MovieDetails = ({ match }) => {
    const movie_id = match.params.id;
    const [movieDetail, setMovieDetail] = useState([]);
    const [genres, setGenres] = useState([]);

    useEffect(() => {
        (async () => {
            const fetchMovieDetails = await yts.get(`api/v2/movie_details.json/`, {
                params: {
                    movie_id,
                },
            });

            setMovieDetail(fetchMovieDetails.data.data.movie);
            setGenres(fetchMovieDetails.data.data.movie.genres);

        }) ();
    },[movie_id] )

    return (
        <div className="movie-detail">
            <div className="row">
                <div className="col-sm-5">
                    <img  className="img-fluid" src={movieDetail.large_cover_image} alt={movieDetail.title}/>
                </div>
                <div className="movie-detail__all col-sm-7">
                    <h3 className="movie-detail__all__title">{movieDetail.title}</h3>
                    <h4 className="movie-detail__all__year"> {movieDetail.year}</h4>
                    <h5 className="movie-detail__all__genre">{genres.map((genre, i) => {
                                return (<i key={i}>{genre} /</i>);
                            })}
                    </h5>
                    <p className="movie-detail__all__description">{movieDetail.description_full}</p>
                    <button>
                         <Link  style={{ color: '#000', fontWeight: 'Bold' }} to="/">Back</Link>
                 </button>
                </div>
            </div>
            </div>

    )
}

export default MovieDetails

We also created a button that takes us back to the home page. And our app is up and ready to run.

You can view the live app here [ movie-appfa3b68.netlify.app ].

Thanks for reading my article you're awesome.