DEV Community

Cover image for React Tutorial - Build a Movie List Generator with React and HarperDB
Kingsley Ubah
Kingsley Ubah

Posted on • Edited on • Originally published at ubahthebuilder.tech

React Tutorial - Build a Movie List Generator with React and HarperDB

In this tutorial, we are going to be building a simple movie generator which automatically generates a new movie every 40 seconds. It will also contain a button called “Generate New Movie” to display another movie on demand.

This app will display a movie along with its title, release date, fan rating, time duration, a short description, star casts, name of directors and finally a button which links to the movie’s IMDb page.

You can access the complete code for this project from its GitHub repository.

HOW ARE WE GOING TO BUILD IT?

As it is with most other web apps, this app is going to be comprised of both a front-end and a back-end. The front-end is the part the user sees and interacts with. In our app, our front-end will be made up of the movie's cover image, movie information as well as a button which will link to the movie’s IMDb page. The back-end is where our movie data, such as the movie title, description, actors, picture etc. will be coming from.

The app is going to automatically generate a new random movie every 40 seconds.
The front end of our app will be built using React. React is a Front-End JavaScript library used for building reusable UI components such as Buttons, Navigation Menus, Images, Cards and so on.

We will also style our components using pure CSS.

OUR BACKEND

The Back-End of a website typically contains a database, which is a program used to store data and manage data. The data for our project will have to be stored somewhere. The database also has to be accessible over an API, this is so that our Front-End can access the data and display it to the user.

For this role, I have an interesting tool to present: HarperDB

WHAT IS HARPERDB?

HarperDB is database and data management software. HarperBD is incredibly fast, even proven to be 37 times faster than MongoDB. A database’s speed refers to how fast it takes to read and write data into its records as well as make computations on such data.

HarperDB is also incredibly flexible. It allows you do the following:

  • Make queries to a single endpoint
  • Use both SQL and NoSQL to query your database
  • Upload data in JSON and with SQL queries.

If you are working with lots of data, you can import it all in one step in a CSV file!
You don’t have to define the data types for your data, HarperDB dynamically does it for you!

Not to mention their simple interface for managing your cloud instance without any hassles.

As I said, very flexible.

PREREQUISITES

To build this app, basic knowledge of the following languages and tools is assumed:

  • Npm or any other package managers: This is needed to install React and a React HarperDB hook called use-harperdb to your project. NPM stands for Node Package Manager. This is a tool which connects your local project to the npm registry, where millions of public code, such as React and useharperdb are hosted. It also helps you manage this code, once installed. Make sure to have a node version of at least 12.xx installed on your machine. You can check your node version with this command: node -v

  • SQL: In this project, we are only going to be using one or two basic queries, so don’t worry if you don’t know much of it. SQL stands for Structured Query Language. It is a popular language used in querying relational databases. We will use it in our hook to query our HarperDB cloud instance for data.

  • React: Our user interface is going to be built with React. If you know JavaScript, then learning React is comparatively easy.

  • A HarperDB account: If you don’t have a HarperDB account, you will need to create one. Don’t worry, it's completely free. I will show you how to create one.

  • CSS: A little CSS is going to be used in styling our elements.

What is a hook in React?

In the past, to work with data in a React component, you had to define the component as a class component. This changed when React introduced hooks. Simply put, hooks are functions which allow you to work with data in a non-class (aka functional) React component.

Thanks to this, you don’t have to define a React class component just to manage state data inside of it.

The use-harperdb hook allows you to hook your app into your cloud database instance to obtain data. Think of it as a bridge between your React app (Front-End) and the HarperDB database (Back-End).

SETTING UP THE DATABASE

HarperDB is flexible. It allows you to use its services either by setting up your own local HarperDB server or using the serverless architecture. In this project, we will be using the serverless architecture. This means that we will not be implementing a server (that is, the backend) on our local machine. Instead, we will leverage HarperDB’s cloud infrastructure to manage our movie data and make it available for our app.

SETTING UP A HARPERDB CLOUD INSTANCE

First, I am going to assume that you have created your free account like I asked earlier. If you haven’t, go over and sign up .

HarperDB-Start for free.png - Create a free account

You will be asked to provide your name, a valid e-mail and a sub-domain name for your cloud instance. With it, they will create a sub-domain name for you.

Studio-HarperDB- password.png - Make sure to select a strong password

Next, we create a cloud instance:

Studio-HarperDB - instance info.png - Fill in your details

Here, you will be told to add an Instance name. Don’t worry, you can name it whatever you can easily remember, however, it is best to make it descriptive. To create your Instance URL, which you will need on your app when querying for data, HarperDB will combine your Instance Name to your Subdomain Name. You will also be prompted to set your Instance credentials (username and password).

Next, we select the Instance Specifications. For the sake of this tutorial, we will go with the free plans. Also, you will need to pick a region for your instance.

Studio-HarperDB -  more instance.png - Choosing free plans

Click on “Confirm Instance Details” and you will be moved to a page which contains all your instance’s information. Now, copy your instance URL, your username as well as your password and save it somewhere, we will need it later.

Studio-HarperDB - confirm instance.png - Save your URL, username and password

When done, click the “Add Instance” button. You will be moved to a page which shows your instance card. Your instance will need some time to set up initially before you can use it, we can do a few things while we wait.

Studio-HarperDB - creating instance.png - Setting up instance

SETTING UP OUR APP

While our cloud instance is still being set up, we take the opportunity to set up the project directory for our app.

First, we initialize our project by running the following command on any command terminal:

npx create-react-app harperdb-movies-generator
Enter fullscreen mode Exit fullscreen mode

This command will create a folder called harperdb-movies-app as well as install all of the dependencies we need for our project, including React and the ReactDOM, so we don’t have to do it manually.

Next we are going to run the command to bring the use-harperdb hook into our project. This hook will help us connect to our cloud instance. To install it, we run the following command on our command line:

npm install use-harperdb
Enter fullscreen mode Exit fullscreen mode

That’s all for the setup!

Integrating HarperDB to your React App

Now that the use-harperdb hook has been installed, we have to do one more thing to be able to access data from your database and make CRUD operations on it: We have to connect your app to your cloud instance. We will do this with the HarperDBProvider.

Before getting into that, we have to do something first. When building a CRUD application, it is not a good practice to expose private credentials such as our API keys to other people, especially if we are intending on pushing the code to a public repo like GitHub.

To protect any sensitive credentials, we will need to store it as an environmental variable. This is just a file where we store sensitive credentials such as our passwords, API keys and in our current case, our cloud instance credentials (URL, username and password).

Create an .env in the root of your directory. You create this file in your code editor, right click on the root directory (harperdb-movie-generator) and select the “create new file” option. Name this file .env and press enter. This will create an .env file inside of harperdb-movie-generator. After this, define the following variables:

REACT_APP_DB_URL=**
REACT_APP_USER=**
REACT_APP_PASSWORD=**
Enter fullscreen mode Exit fullscreen mode

Make sure you use the same format and pass in the correct details about your own cloud instance in place of the double asterisk. Fill in your Instance URL, your Instance Username and your Instance Password, which I had earlier told you to save somewhere. React will read all environmental variables that use the REACT_APP as prefix, and will then dynamically pass in the value where needed.

With the .env file created, our next action will be to wrap our entire React app inside the imported HarperDBProvider.

HarperDBProvider will ensure that our app has the context of the HarperDB database.
To wrap our React App inside the provider, we go over to index.js inside our project, import the provider and securely pass in those environmental variables into the provider, so it will know which instance to connect our Front-End to:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { HarperDBProvider } from 'use-harperdb';


ReactDOM.render(
  <React.StrictMode>
    <HarperDBProvider
    url={process.env.REACT_APP_DB_URL}
    user={process.env.REACT_APP_USER}
    password={process.env.REACT_APP_PASSWORD}
    >
      <App />
    </HarperDBProvider>
  </React.StrictMode>,
  document.getElementById('root')
);
Enter fullscreen mode Exit fullscreen mode

POPULATING OUR DATABASE WITH DATA

If you remember correctly, we had left the cloud instance while it was still being set up. By now, we should have our instance all set and ready to serve data. In that case, we will see the OK status on your instance:

Studio-HarperDB- okay.png - Instance now set

Our cloud instance should be good-to-go with our front-end hooked up to our instance as well. However, our Front-End will be useless if it doesn’t have any data (that is, movies) to display to the user.

Hence, we will first need to populate our database with data.

But before that, we will need to create a schema for our movie data. You can think of a schema as a collection of tables in our database. I simply call my own schema "collection":

Studio-HarperDB - collection.png - Creating our schema and a table inside of it

Next, we create our table. I simply called mine "movie". A table will consist of records of individual movies. Each movie record must have a hash_attribiute. A hash_attribute is simply a column with unique keys which identifies that particular row of data and distinguishes it from the next row. We are simply using the “id” column as our hash_attribute.

Since we are creating an app with more than one movie, our table will consist of more than one row of movies (aka records of data). Also, since each movie has many properties such as title, year, release date and so on, it will have more than one field of information.

You can upload the movies one by one with a single JSON object or upload a full collection of movies with an array of JSON objects.

HarperDB allows us to upload data in three main ways:

  1. By making SQL or NoSQL queries to create data on our database.
  2. Defining a single JSON object (for only one record) and an array of JSON data (for multiple records)
  3. Importing and loading data with a CSV file

To upload a single movie data, we create a JSON object which contains all the movie information. Here is an example JSON data:

{
  cover: 'https://res.cloudinary.com/ubahthebuilder/image/upload/v1627129180/avengers_endgame_ilqzqj.png',
  date: 2017,
  description: 'After the devastating events of Avengers: Infinity War (2018), the universe is in ruins. With the help of remaining allies, the Avengers assemble once more in order to reverse Thanos actions and restore balance to the universe.',
  directors: [
    'Anthony Russo',
    'Joe Russo'
  ],
  genres: [
    'Action',
    'Adventure',
    'Drama'
  ],
  hours: 3,
  id: 1,
  minutes: 1,
  rating: 8.4,
  stars: [
    'Robert Downey',
    'Chris Evans',
    'Mark Ruffalo'
  ],
  title: 'Avengers: End Game',
  website: 'https://www.imdb.com/title/tt4154796/',
  writers: [
    'Christopher Markus',
    'Stephen McFeely'
  ]
}
Enter fullscreen mode Exit fullscreen mode

Navigate to the movie table inside collection and click on the + sign at the top right corner of the page, which is highlighted in the following image

addmovie.png - Adding a new movie record into our table

Copy the previously defined JSON object and paste it into the space provided replacing everything there for formatting reasons. Click the green button to save the information into the movies table

adddata.png - Paste in the JSON object

Once we are done with uploading, our table should look something like this:

Studio-HarperDB FULL TABLE.png - Eight Movies in the table

Note that you can make use of the data from this project’s GitHub repository to insert multiple records of movies at once.

BUILDING UP OUR UI AND QUERYING THE DATABASE

Now with the data ready, we need to display it on our Front-End for the user to see and interact with.

First, we need to alter our app.js file:

import React from 'react';
import './App.css';
import Movie from './components/Movie';

function App() {
  return (
    <div className="App">
      <div className="main-container">
        <header>
          <h1 className="heading">Movie List</h1>
          <h3> A Simple Movie Generator built with React and HarperDB</h3>
        </header>
        <div>
          <Movie />
        </div>
      </div>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This will be the top level component in our project.

We import the React, React DOM libraries as well as the stylesheet App.css for our entire app.

Next, in the App.css file we define our app component which returns the Header elements as well as the Movie component.
Here is the style for our entire app:

@import url('https://fonts.googleapis.com/css2?family=Lato:wght@300&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@500&display=swap');

/* Base Styles */

body {
  font-family: "lato", sans-serif;
  color: white;
  background-color: #082032;
}

a {
  color: black;
  font-family: "roboto", sans-serif;
  font-size: 50px;
  text-decoration: none;
  display: inline-block;
}


h1 {
  text-align: center;
  font-family: "roboto", sans-serif;
  font-size: 60px;
  font-weight: 80px;
}

h3 {
  text-align: center;
}

p {
  font-weight: 400px;
}

span {
  color: #FFF338;
}

ul {
  list-style-type: none;
  display: flex;
  margin-left: 339px;
}


li {
  outline-color: #2C394B;
  outline-style: inset;
  outline-width: 2px;
  outline-offset: 5px;
  margin: 11px;
  padding: 0px, 20px;
}

img {
  height: 500px;
  width: 100%;
}


/* Classes */

.movie-cover {
  max-width: 800px;
  width: 800px;
  background-color: #2C394B;
  margin: 0 auto;
  border-radius: 10px;
}

.circle {
    background-color: transparent;
    margin-right: 37px;
    text-align: center;
    margin-top: 50px;
    border:3px solid #FFF338;
    height:90px;
    border-radius:50%;
    -moz-border-radius:50%;
    -webkit-border-radius:50%;
    width:90px;
}

.ratings {
  font-size: 30px;
  margin-top: 12px;
}

.big-half , .small-half {
  font-family: "roboto", sans-serif;
  font-style: oblique;
  color: white;
}

.small-half {
  color: #DAD0C2;
  font-size: 19px;
}



.visit-movie-button {
  margin: 30px, 20px;
  padding: 10px, 30px;
  position: relative;
  top: 50px;
  left: 120px;
  font-size: 20px;
  outline-style: solid;
  color: #FFF338;
  outline-color: #FFF338;
  outline-offset: 10px;
}


.generate-movie-button {
background-color: #FFF338;
padding: 0.5em 1.2em;
font-size: 20px;
text-decoration: none;
position: relative;
top: 50px;
left: 250px;
text-transform: uppercase;
}

.action-buttons {
  width: inherit;
}


.title {
  font-size: 50px;
  padding-top: 40px;
  padding-left: 30px;
  margin-bottom: 0;
}

.top-information {
  display: flex;
  justify-content: space-between;
}

.supporting-info {
  padding-left: 30px;
  font-weight: bold;
  margin-bottom: 20px;
}

.lower-information {
  font-family: "roboto", sans-serif;
  width: 800px;
  max-width: 800px;
  margin-left: 380px;
}
Enter fullscreen mode Exit fullscreen mode

Once again, you can access the complete code for this project from its Github repository.

THE MOVIE COMPONENT

We now need to add our movie component. We will start by creating a new folder under the 'src' directory named 'component’. We then need to create a new file inside that new file named 'movie.js'.This is where the spicy things start to happen:
In addition to the React and ReactDOM libraries, we are going to import the use-harperdb hook (function) as well.

We are going to execute the use-harperdb function, passing in an object as an argument. Inside the object, we need to supply at least a single query property. This property determines what kind of operation we want to carry out on our database.

import React from 'react';
import { useHarperDB } from 'use-harperdb';

function Movie() {
let [data, loading, error, refresh] = useHarperDB({
    query: {
      operation: 'sql',
      sql: `select * from collection.movie where id = ${Math.floor(Math.random() * 8) + 1}`
    },
    interval: 40000 // 40 Seconds
  }
  )

  // CODE CONTINUES
Enter fullscreen mode Exit fullscreen mode

The first property, which is the operation property, specifies how you want to query the data. In our example, we are going to do so with a SQL command. The second property within the query is the SQL property. This is where we write our SQL queries for any CRUD operation we want to carry out. In our case, we simply want to select all fields from a randomly selected movie between 1-8, from the database, which we have denoted by the following SQL clause:

select * from collection.movie where id = ${Math.floor(Math.random() * 8) + 1}`
Enter fullscreen mode Exit fullscreen mode

After the query, another optional property we can define is the interval property. With this property, you can specify how long you want your app to wait before it automatically generates a fresh query to the database.

Executing the useHarperDB function with those parameters correctly passed in will return us an Array containing some important things. Below are four important items we will get from useharperdb:

  • loading: This is a Boolean which specifies if the database is still processing data or not. That way, you can optionally display a “loading” spinner

  • error: This indicates if an error was encountered while querying the database.

  • refresh: Assuming you don’t set an interval property, you can call this function whenever you want to fetch new data.

  • data: The main thing. If all things go well, HarperDB will return our data to this variable.

DISPLAYING DATA IN OUR FRONT END

With our data now successfully returned from the database, it’s time pass it into our React template:


if(loading) {
    return <div> Loading... </div>
  }

if(data) {
      return (
<>
<div className="movie-cover">
  <div className="top-information">
    <h2 className="title">{data[0].title}</h2>
    <div className="circle">
      <div className="ratings">
        <span className="big-half">{data[0].rating}</span>/<span className="small-half">10</span>
      </div>
    </div>
  </div>

  <div className="supporting-info">
    <span className="year">{data[0].date}</span> -
    <span className="time">{data[0].hours}h:{data[0].minutes}m</span>
  </div>
  <div className="image">
    <img src={data[0].cover} alt="Movie Image" />
  </div>
</div>

<div className="genres">
  <ul className="movie-genres">
    {data[0].genres.map((genre, index) => {
    return (
    <li key={index}><span className="movie-genre-item">{genre}</span></li>
  )
    })}
  </ul>
</div>

<div className="lower-information">
  <p>{data[0].description}</p>

  <hr />
  <p> Starring: {data[0].stars.map((star, index) => {
    return (
    <span key={index}>{star} - </span>
    )
    })}
  </p>
  <hr />
  <p> Writers:
    {data[0].writers.map((writer, index) => {
      return (
    <span key={index} className="writer">{writer} - </span>
    )
    })}
  </p>
  <hr />
  <p>Directors:
    {data[0].directors.map((director, index) => {
      return (
    <span key={index} className="director">{director} - </span>
    )
    })}
  </p>
  <hr />
  <div className="action-buttons">
    <a href={data[0].website} className="visit-movie-button">Visit Movie</a>
    <a href="" className="generate-movie-button" onClick={refresh}>GENERATE NEW MOVIE</a>
  </div>
</div>
</>
)
} else {
    return (
      <div>Sorry No Data
        {error}
      </div>
  )
}

}
Enter fullscreen mode Exit fullscreen mode

If you are familiar with React, this shouldn’t be foreign to you. However, I am going to explain what we did here:

  • As I stated, the useharperdb function will return us our data. If you query to get all of the movies, it will return an array of movies. Since we queried for only a single movie, it will return us an object containing the data of a single movie.

  • Next, we have to check if the data was returned. If there is no data, we display a simple div displaying a "Sorry No Data" message.

  • Since we did receive data, we passed in the data into our template. We extract each field from the object and pass it into the correct template.

When finished, we run the following command on the command line

npm start
Enter fullscreen mode Exit fullscreen mode

That should start our development server at https://localhost:3000 and If everything goes well, we should see our app live on the browser with some cool movie data!

That's it for our app!

DEPLOYING THE APP TO GITHUB PAGES

Welcome to the last section of the tutorial. We will be deploying the fresh app to GitHub pages for the world to see.

Github pages.png - GitHub site

First, you need to have a GitHub account. If you don’t, you can create one for yourself here

Also, you need to have Git version control software installed on your local machine. This is something every software developer should already have. However, if you don’t, you can install it from here .

First thing to do is to create a new repository for our project on our GitHub Account:

Create-a-New-Repository.png - Creating a new repository

repo.png

Then, we go back to the terminal and run the following command:

npm install gh-pages --save-dev
Enter fullscreen mode Exit fullscreen mode

This will save GitHub Pages to our project as a dev dependency.
When this is done, we go over to our project folder and open the package.json file, we should find gh-page safely installed there under the dev dependency:

"devDependencies": {
    "gh-pages": "^3.2.3"
  }
Enter fullscreen mode Exit fullscreen mode

Next, we are going to do the following three things:

  • Navigate to your project directory (harperdb-movie-generator) and select the package.json file. On the top of our package json, we will add the following data (replace the template with yours):
"homepage":  https://{Your GitHub username here}.github.io/{Your_Project_Name}.git
Enter fullscreen mode Exit fullscreen mode

To find your GitHub username and the name of your repository, navigate to the newly created repo on GitHub. At the top, you can find your GitHub username and the project name next to it. Copy both of them and fill it into the aforementioned template, make sure to append .git at the end of your project name.

project name and username.png - Your GitHub Information

The essence of adding the “homepage” field is to specify the URL where our app will eventually get hosted at. Make sure to put a comma at the end, so your package json will be parsed correctly.

  • Go over to the "scripts" field within the same file and pass in the following data being sure you maintain proper indentation:
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
Enter fullscreen mode Exit fullscreen mode

This is what you will run when you are ready to deploy to GitHub pages.

  • Finally, we are going to initialize Git in your project. To do this, simply navigate to our project directory on the command line and run the following command:
cd projects/harperbd-movie-generator

git init
Enter fullscreen mode Exit fullscreen mode

Now, everything is set!

The only thing left to do is deploy our app to GitHub pages. To do this, we run the following command:

npm run deploy
Enter fullscreen mode Exit fullscreen mode

And voila!, our app will immediately be deployed to GitHub pages.

VIEWING YOUR LIVE APP

Our app is now live at this point, but we have to see what it looks like. Hence, you have to get it’s URL.

Go over to your GitHub profile and click the repository tab. Select your newly created repo and go to the settings page, scroll down a bit. You will find the GitHub pages section. Click on “check it out here!”

GIT1.png

In the following page, inside Source, switch the Branch to “gh-pages” and file-path to “root”. Within a few minutes, your app will be all set. Copy the URL from the page and paste into a new browser window.

git2.png - App is now live at the URL

And behold, your live project.

WRAPPING UP

This project was built with React and HarperDB. HarperDB is a great choice for your data management and back-end operations.

Not only is it flexible but also very easy to integrate, as we have seen in this tutorial.
You shouldn’t stop here. You can improve on your skills by building some other cool projects with this same stack. Thanks to HarperDB’s free plan, you don’t have to pay anything.

Once again, you can grab the code for this project from its GitHub repository .

Want to reach out for any suggestions? You can get me on Twitter

That’s it. Thank you for following along and have a great week.

Top comments (0)