Build a Next.js Interactive Web-Based Simple Movie Database

Written by

in

In the digital age, we’re constantly bombarded with choices. Deciding what to watch can sometimes feel overwhelming. Wouldn’t it be great to have a simple, easy-to-use application to explore movies, see their details, and perhaps even save your favorites? In this tutorial, we’ll build a simple movie database application using Next.js, a powerful React framework, that allows you to fetch movie data from an API, display movie information, and implement a basic search functionality. This project is perfect for beginners and intermediate developers looking to deepen their understanding of Next.js, API interactions, and front-end development principles.

Why Build a Movie Database?

Creating a movie database is an excellent project for several reasons:

  • Practical Application: It’s a real-world application that many people can relate to and find useful.
  • API Integration: It gives you hands-on experience working with APIs, which is a crucial skill in modern web development.
  • Data Handling: You’ll learn how to fetch, parse, and display data effectively.
  • User Interface: You will practice building a user-friendly interface.
  • Next.js Fundamentals: It covers essential Next.js concepts like routing, dynamic routes, and fetching data.

By the end of this tutorial, you’ll have a fully functional movie database application and a solid understanding of how to build interactive web applications with Next.js.

Prerequisites

Before we begin, make sure you have the following:

  • Node.js and npm (or yarn): Installed on your computer.
  • A Code Editor: Such as VS Code, Sublime Text, or Atom.
  • Basic Knowledge of JavaScript and React: Familiarity with these technologies is helpful but not strictly required.

Setting Up the Project

Let’s start by creating a new Next.js project. Open your terminal and run the following command:

npx create-next-app movie-database

This command will create a new Next.js project named “movie-database”. Navigate into the project directory:

cd movie-database

Now, start the development server:

npm run dev

Open your browser and go to http://localhost:3000. You should see the default Next.js welcome page.

Installing Dependencies

For this project, we’ll use a few dependencies to make our lives easier. We’ll use the following dependencies:

  • axios: For making API requests.
  • react-icons: For icons.
  • tailwindcss and postcss and autoprefixer: For styling.

Install them using npm or yarn:

npm install axios react-icons tailwindcss postcss autoprefixer

Next, we need to configure Tailwind CSS. Run the following commands:

npx tailwindcss init -p

This will create two files: `tailwind.config.js` and `postcss.config.js`. Open `tailwind.config.js` and configure the template paths:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './app/**/*.{js,ts,jsx,tsx,mdx}',
    './pages/**/*.{js,ts,jsx,tsx,mdx}',
    './components/**/*.{js,ts,jsx,tsx,mdx}',

    // Or if using `src` directory:
    './src/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {
      // Add your custom theme here
    },
  },
  plugins: [],
}

Then, add the Tailwind directives to your global CSS file. Open `src/app/globals.css` or `styles/globals.css` (depending on your project setup) and add the following:

@tailwind base;
@tailwind components;
@tailwind utilities;

Fetching Movie Data from an API

We’ll use The Movie Database (TMDb) API to fetch movie data. You’ll need an API key, which you can get by creating an account on The Movie Database website. Once you have your API key, store it securely (e.g., in a `.env.local` file).

Create a `.env.local` file in the root directory of your project and add your API key:

TMDB_API_KEY=YOUR_API_KEY

Replace `YOUR_API_KEY` with your actual API key.

Now, let’s create a function to fetch movie data. We’ll create a `utils` directory and a `api.js` file inside it:

mkdir utils
touch utils/api.js

In `utils/api.js`, add the following code:

import axios from 'axios';

const API_KEY = process.env.TMDB_API_KEY;
const BASE_URL = 'https://api.themoviedb.org/3';

export const getPopularMovies = async () => {
  try {
    const response = await axios.get(`${BASE_URL}/movie/popular?api_key=${API_KEY}`);
    return response.data.results;
  } catch (error) {
    console.error('Error fetching popular movies:', error);
    return [];
  }
};

export const getMovieDetails = async (movieId) => {
  try {
    const response = await axios.get(`${BASE_URL}/movie/${movieId}?api_key=${API_KEY}`);
    return response.data;
  } catch (error) {
    console.error(`Error fetching movie details for ID ${movieId}:`, error);
    return null;
  }
};

export const searchMovies = async (query) => {
  try {
    const response = await axios.get(`${BASE_URL}/search/movie?api_key=${API_KEY}&query=${query}`);
    return response.data.results;
  } catch (error) {
    console.error('Error searching movies:', error);
    return [];
  }
};

This code defines three functions:

  • `getPopularMovies`: Fetches a list of popular movies.
  • `getMovieDetails`: Fetches details for a specific movie by its ID.
  • `searchMovies`: Searches for movies based on a query.

Creating Components

Let’s create some components to structure our application. We’ll create a `components` directory. Inside this directory, we’ll create the following components:

mkdir components
touch components/MovieCard.js
touch components/MovieDetails.js
touch components/SearchBar.js

MovieCard.js

This component will display a single movie card with its title and poster.

import Image from 'next/image';
import Link from 'next/link';

const MovieCard = ({ movie }) => {
  const { id, title, poster_path } = movie;
  const imageBaseUrl = 'https://image.tmdb.org/t/p/w500';
  const imageUrl = poster_path ? `${imageBaseUrl}${poster_path}` : '/no-image.png';

  return (
    
      <div>
        
        <div>
          <div>{title}</div>
        </div>
      </div>
    
  );
};

export default MovieCard;

MovieDetails.js

This component will display the details of a single movie.

import Image from 'next/image';

const MovieDetails = ({ movie }) => {
  if (!movie) return <p>Loading...</p>;

  const { title, overview, poster_path, vote_average } = movie;
  const imageBaseUrl = 'https://image.tmdb.org/t/p/w500';
  const imageUrl = poster_path ? `${imageBaseUrl}${poster_path}` : '/no-image.png';

  return (
    <div>
      <h2>{title}</h2>
      <div>
        
        <div>
          <p>{overview}</p>
          <p>Rating: {vote_average}/10</p>
        </div>
      </div>
    </div>
  );
};

export default MovieDetails;

SearchBar.js

This component will allow users to search for movies.

import { useState } from 'react';

const SearchBar = ({ onSearch }) => {
  const [query, setQuery] = useState('');

  const handleChange = (event) => {
    setQuery(event.target.value);
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    onSearch(query);
  };

  return (
    
      
    
  );
};

export default SearchBar;

Creating Pages

Now, let’s create the pages for our application. Next.js uses the `pages` directory for routing. We’ll create the following pages:

mkdir pages
touch pages/index.js
touch pages/movie/[id].js

pages/index.js

This is the home page, which will display a list of popular movies and the search bar.

import { useState, useEffect } from 'react';
import { getPopularMovies, searchMovies } from '../utils/api';
import MovieCard from '../components/MovieCard';
import SearchBar from '../components/SearchBar';

const Home = () => {
  const [movies, setMovies] = useState([]);
  const [searchQuery, setSearchQuery] = useState('');

  useEffect(() => {
    const fetchMovies = async () => {
      const data = await getPopularMovies();
      setMovies(data);
    };
    fetchMovies();
  }, []);

  const handleSearch = async (query) => {
    setSearchQuery(query);
    if (query) {
      const data = await searchMovies(query);
      setMovies(data);
    } else {
      const data = await getPopularMovies();
      setMovies(data);
    }
  };

  return (
    <div>
      <h1>Popular Movies</h1>
      
      <div>
        {movies.map((movie) => (
          
        ))}
      </div>
    </div>
  );
};

export default Home;

pages/movie/[id].js

This is the dynamic route for displaying movie details. The `[id]` part indicates a dynamic route parameter.

import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import { getMovieDetails } from '../../utils/api';
import MovieDetails from '../../components/MovieDetails';

const MovieDetailPage = () => {
  const router = useRouter();
  const { id } = router.query;
  const [movie, setMovie] = useState(null);

  useEffect(() => {
    const fetchMovieDetails = async () => {
      if (id) {
        const data = await getMovieDetails(id);
        setMovie(data);
      }
    };
    fetchMovieDetails();
  }, [id]);

  return (
    <div>
      
    </div>
  );
};

export default MovieDetailPage;

Styling the Application

We’ve already configured Tailwind CSS. Now, let’s add some basic styling to our components. You can add more styles as needed.

Here are some examples of how to apply styles using Tailwind CSS:

  • Container: `container mx-auto p-4`
  • Heading: `text-3xl font-bold mb-4`
  • Card: `rounded overflow-hidden shadow-lg hover:shadow-xl transition-shadow duration-200`
  • Image: `w-full h-auto`
  • Text: `text-gray-700`

Testing the Application

Now, let’s test our application. Run the development server if it’s not already running:

npm run dev

Open your browser and navigate to http://localhost:3000. You should see a list of popular movies and a search bar. Try searching for a movie. Click on a movie to view its details.

Common Mistakes and How to Fix Them

Here are some common mistakes and how to fix them:

  • API Key Issues: If you get an error related to the API key, double-check that your API key is correctly set in your `.env.local` file and that you’re referencing it correctly in your code (using `process.env.TMDB_API_KEY`). Also, make sure that you have enabled the API in your TMDb account.
  • CORS Errors: If you encounter CORS (Cross-Origin Resource Sharing) errors, it’s likely an issue with the API’s configuration. This is less common with public APIs, but if you’re making requests from a different origin than where your API is hosted, you might need to configure CORS on the API server. For local development, you might be able to use a browser extension to disable CORS temporarily, but this isn’t a long-term solution.
  • Incorrect Data Paths: Ensure that you are accessing the correct properties from the API response. Use `console.log` to inspect the data returned by the API and verify the correct data paths. For example, if the API returns the poster path under the key `poster`, your code should use `movie.poster` to access it.
  • Image Loading Issues: If images aren’t loading, check the image URL. Ensure the base URL is correct and the poster path from the API is appended correctly. Also check your Next.js image optimization settings if you are using the built-in `Image` component.
  • Typographical Errors: Always check for typos in your code, especially in component names, variable names, and API endpoints. Typos can lead to unexpected behavior and errors.

Key Takeaways

  • Next.js Fundamentals: You’ve learned how to create a Next.js project, set up routing, fetch data from an API, and build reusable components.
  • API Integration: You’ve gained practical experience working with a public API to fetch and display data.
  • Component-Based Architecture: You’ve learned how to break down a complex application into smaller, manageable components.
  • Styling with Tailwind CSS: You’ve used Tailwind CSS to style your application.

FAQ

Q: How can I deploy this application?

A: You can deploy your Next.js application to various platforms, such as Vercel (which is recommended, as it’s built by the Next.js team), Netlify, or AWS. You’ll typically need to push your code to a repository (like GitHub) and then connect your deployment platform to that repository. The platform will handle the build and deployment process.

Q: How can I add more features to this application?

A: You can enhance this application by adding features such as:

  • User Authentication: Allow users to create accounts and save their favorite movies.
  • Movie Trailers: Integrate movie trailers from YouTube or other providers.
  • Pagination: Implement pagination to load movies in batches.
  • Filtering and Sorting: Add features to filter and sort movies based on different criteria (genre, release date, rating, etc.).
  • Responsive Design: Ensure the application looks good on all devices.

Q: Where can I find more information about Next.js and Tailwind CSS?

A: You can find more information at:

Q: How can I handle errors more gracefully?

A: You can improve error handling by:

  • Implementing error boundaries: Use React’s error boundaries to catch errors in child components and display a fallback UI.
  • Adding loading states: Display loading indicators while data is being fetched.
  • Showing error messages: Display user-friendly error messages if API requests fail.
  • Logging errors: Log errors to a service like Sentry or Bugsnag to monitor application health.

Q: How can I improve the application’s performance?

A: Performance can be improved by:

  • Image optimization: Use Next.js’s built-in image optimization to serve images in optimized formats.
  • Code splitting: Use dynamic imports to split your code into smaller chunks.
  • Caching: Implement caching strategies to reduce the number of API requests.
  • Server-side rendering (SSR) and Static Site Generation (SSG): Consider using SSR or SSG to pre-render pages.

This tutorial provides a solid foundation for building interactive web applications with Next.js. With the knowledge you’ve gained, you can now explore more advanced features and build even more complex projects.