Building a React Movie Application.

thankgod

Eboreime ThankGod

Posted on January 20, 2021

Building a React Movie Application.

In this article, we are going to build a react movie application for searching and discovering movies using the OMDB API. You can clone the repo directly https://github.com/Tk-brainCodes/OMDB-Movies.git.
View Live-Demo.

Step 1 (Get An API Key):

Proceed to this link to get a free API key for this project:
Link: API Key.

The purpose of the API key is to track how the API is been used by the user and how many requests are made a day. This API offers 1,000 search limits a day. The API key will be forwarded to your email address, now you can start using the OMDB API.

Project Setup:

In your terminal or command prompt run these commands:
run: npx create-react-app OMDB-movies to create a new react app.
cd into the directory: cd OMDB-movies
run: npm install axios for requesting data from an API.
Then run: npm start or yarn start to start the react application server. You should see the react logo spinning in your browser:

Alt Text

Creating Components:

In the App.js component get rid of everything. It should look like this:




import './App.css';


function App() {
  return (
    <div className="App">

    </div>
  );
}

export default App;


Enter fullscreen mode Exit fullscreen mode

Next inside the src folder create a new folder and name it Components.Inside the Components folder create three folders for each components.

  1. Card folder
  2. Header folder
  3. Movies folder

Your project structure should look like this:

Alt Text

Next, we are going, to begin with, the Header.js component. Inside the Header components folder create a Header.js component and Header.css file. The code below are the basic CSS code for our Header.css file.



/*HEADER.CSS*/


@import url('https://fonts.googleapis.com/css2?family=Nanum+Gothic:wght@800&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Pacifico&display=swap');
.input  {
    padding: 20px;
    width: 300px;
}

.heading {
    font-size: 17px;
    font-weight: bolder;
    padding: 5px;
    font-family: 'Nanum Gothic', sans-serif;
}

.paragraph {
    padding: 5px;
    color: #3da4ab ;
}

.title {
    font-family: 'Pacifico', cursive;
    color: white;
}

.header {
    display: flex;
    align-items: center;
    justify-content: space-evenly;
    padding: 20px;
}

.name {
    font-size: 20px;
    padding: 10px;
}

.search {
    color: white;
    font-weight: bolder;
}

.search input[type="text"]{
    border: 1px solid #f6cd61;
    background-color: black;
    color: white;
    text-transform: uppercase;
    font-weight: bolder;
    border-radius: 2px;
    width: 40em;
    padding: 20px;

}

.search input[type="text"]:focus
{
    outline: 0;
}

button {
    background-color: #dfad31;
    border: none;
    color:white;
    font-weight: bolder;
    font-size: 16px;
    padding: 20px;
    cursor:pointer;
}


.norminee {
    border-radius: 4px;
    background: rgb(9, 136, 9);
}

/* ===========================
   ====== Medua Query for Search Box ====== 
   =========================== */

@media only screen and (min-width : 150px) and (max-width : 780px)
{
    .search
    {
        width: 40em;
        margin: 0 auto;
    }

}


.link {
    text-decoration: none;
    list-style-type: none;
}


Enter fullscreen mode Exit fullscreen mode

Next, we are going to import our CSS to the Header.js components:



//HEADER.JS

import React from 'react';
import './Header.css';

const Header = () => {
    return (
        <div className="Header">
        <h1>Header Components</h1>
        </div>

    )
}

export default Header;


Enter fullscreen mode Exit fullscreen mode

Our Header.js component is set but no reasonable content, we will come back to that shortly.
Next we are going to set up our Movies.js component. Inside the Movies folder, we created earlier, create a Movies.js component and a Movie.css file. The code below are the basic CSS code for our Movies.css file.



/*MOVIES.CSS*/

@import url('https://fonts.googleapis.com/css2?family=Nanum+Gothic:wght@800&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Pacifico&display=swap');
.input  {
    padding: 20px;
    width: 300px;
}

.cardlist__movies {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    -webkit-box-shadow: 5px 5px 32px 5px rgba(0,0,0,0.43); 
    box-shadow: 5px 5px 32px 5px rgba(0,0,0,0.43);
}

.card {
    margin-left: 20px;
    border-radius: 4px;
    margin-top: 30px;
    margin-bottom: 20px;
}

.movie__image {
    height: 500px;
    width: 350px;
    border-radius: 10px;
}

.flex__card {
    background-color: rgb(14, 13, 13);
    color: #f6cd61 ;
    padding: 20px;
    border-radius: 10px;
    margin-top: 10px;
}

.heading {
    font-size: 17px;
    font-weight: bolder;
    padding: 5px;
    font-family: 'Nanum Gothic', sans-serif;
}

.paragraph {
    padding: 5px;
    color: #3da4ab ;
}

.title {
    font-family: 'Pacifico', cursive;
    color: white;
}

.header {
    display: flex;
    align-items: center;
    justify-content: space-evenly;
    padding: 20px;
}

.name {
    font-size: 20px;
    padding: 10px;
}



Enter fullscreen mode Exit fullscreen mode

In the code below:
I imported Axios we installed earlier and also imported the Header.js component and the Movie.css file.I created a state for movies and queries and created a function searchMovie, inside the searchMoviefunction, I consumed my API and passed in response.data.Search to my setState function, setMovies.In the return statement, I passed in the function and the states as props to theHeader component.



//MOVIES.JS

import React, { useState } from 'react';
import Header from '../Header/Header';
import axios from 'axios';
import './Movies.css'

const Movies = () => {
   //states
    const [movies, setMovies] = useState([]);
    const [query, setQuery] = useState('');

  //Consume the API
    const searchMovie = async (e) => {
        e.preventDefault();

        const API_KEY = "b57e0c63"; //use your personal API Key
        const apiURI = `https://www.omdbapi.com/?i=tt3896198&apikey=${API_KEY}&s=${query}`;

        try {
            const response = await axios.get(apiURI);
            const data = response.data.Search
            console.log(data);

           //setState
            setMovies(data);

        } catch (err) {
            console.error(err);
        }
    }


    return (
        <div className="shoppies">
         {/*Header component*/}
            <Header
                searchMovie={searchMovie}
                query={query}
                setQuery={setQuery}
                movies={movies}
            />
        </div>
    )
}

export default Movies;


Enter fullscreen mode Exit fullscreen mode

Back to our Header.js component:
In the code below:
I destructured the properties that were passed in from the Movies.js component to the Header.js component. Then I created a search form with an onSubmit handler that takes a function searchMovie which was defined in the Movies.js component, and also the onChange handler that has an inline function to update the value that the user types in the input.



//HEADER.JS

import React, { Fragment } from 'react';
import './Header.css';

//destructure props
const Header = ({ searchMovie, query, setQuery, movies }) => {
    return (
        <Fragment>
            <div className="header">
                <h1 className="title">Movie-search</h1>

                {/*Search form*/}

                <div className="search">
                    <form className="search-form" onSubmit={searchMovie}>
                        <label
                            htmlFor="query"
                            className="name"
                        >
                        </label>
                        <input
                            type="text"
                            name="query"
                            placeholder="i.e Guardians of the Galaxy Vol. 2"
                            value={query}
                            onChange={(e) => setQuery(e.target.value)}
                        />
                        <button type="submit">Search</button>
                    </form>
                </div>
            </div>

        </Fragment>
    )
}

export default Header;


Enter fullscreen mode Exit fullscreen mode

Let's see how far we have gone!:
import the Movie.js component to the App.js component.
code below:



//APP.JS


import './App.css';
import Movies from './Component/Movies/Movies';


function App() {
  return (
    <div className="App">
      {/*Movie component*/}
      <Movies />
    </div>
  );
}

export default App;


Enter fullscreen mode Exit fullscreen mode

Now run: npm start to start the app. You would see the header displaying in your browser with the search box.

Alt Text

Right now nothing is been rendered when we search for a movie. Next, we move to the card component containing the movie image, movie title, and movie year.

Inside the card folder we created earlier, create a Card.js component.

In the code below:
I destructured movies which do not yet exist in the Card.js component but in the Header.js component, then filtered any image that does not have a poster image {movies.filter(movie => movie.Poster) and mapped through the arrays of movies using .map((movie,index) => then passed in the {movie.Title} and {movie.Year}.



//CARD.JS


import React from 'react';

const Card = ({ movies }) => {
    return (

        <div className="cardlist__movies">
            {movies.filter(movie => movie.Poster).map((movie, index) => (
                <div className="card" key={index}>
                    <img
                        className="movie__image"
                        src={movie.Poster}
                        alt="postal"
                    />
                    <div className="flex__card">
                        <p className="heading">{movie.Title}</p>
                        <p className="paragraph">{movie.Year}</p>
                        <br />
                    </div>
                </div>
            ))}
        </div>
    )
}

export default Card;


Enter fullscreen mode Exit fullscreen mode

Next we import the Card.js component into the Header.js component and render it at the bottom. Your code should look like this:



//HEADER.JS


import React, { Fragment } from 'react';
import './Header.css';
import Card from '../Card/Card';



const Header = ({ searchMovie, query, setQuery, movies }) => {
    return (
        <Fragment>
            <div className="header">
                <h1 className="title">Movie-search</h1>

                {/*Search form*/}

                <div className="search">
                    <form className="search-form" onSubmit={searchMovie}>
                        <label
                            htmlFor="query"
                            className="name"
                        >
                        </label>
                        <input
                            type="text"
                            name="query"
                            placeholder="i.e Guardians of the Galaxy Vol. 2"
                            value={query}
                            onChange={(e) => setQuery(e.target.value)}
                        />
                        <button type="submit">Search</button>
                    </form>
                </div>
            </div>

             {/*Card component*/}

            <div className="list-movie">
                <Card movies={movies} />
            </div>
        </Fragment>
    )
}

export default Header;


Enter fullscreen mode Exit fullscreen mode

Now if you search for a movie you should see it displaying the poster image, year of release, and name of movie.

Alt Text

Feel free to ask questions in any area you don't understand.
If you like this content you can follow me on Twitter @tkworldclass.

đź’– đź’Ş đź™… đźš©
thankgod
Eboreime ThankGod

Posted on January 20, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related