loading...
Cover image for React Project: Movie App

React Project: Movie App

maj07 profile image Majuran SIVAKUMAR ・3 min read

Hello πŸ‘‹, For my first post on dev.to, I decided to share with you a small tuto about creating a Movie App with React and TypeScript.

Demo https://movie-app-majuran.netlify.app πŸš€

Source code available on Github : Here !

Setup

Before starting coding let's setup our project.

Generate project with CreateReactApp:

I often (to not say always 😁) use Create React App to initiate my React projects.

In order to generate our project run :

npx create-react-app my-movie-app --template typescript
Enter fullscreen mode Exit fullscreen mode

API :

The frontend will have to fetch the data from an API, I choose TMDb 🎬 : It's free, you just need to create an account to get your API key

Please use your API key as an environment variable, in .env file :

REACT_APP_API_KEY=YOUR_API_KEY
Enter fullscreen mode Exit fullscreen mode

The configuration is done, let's start coding. πŸ’»

State Management

Our app components are going to communicate between them.
To handle this, we need a state management, for that, we are going to combine the context API and state hooks

In case, you are not familiar with react hooks. I encourage you, to read ➑️ React Hooks and Context API

// create context
export const MoviesContext = React.createContext<{
  movies: Movie[];
  updateMovies: Function;
}>({
  movies: [],
  updateMovies: Function,
});

function App() {
// get default values
  useEffect(() => {
    discoverMovies()
      .then(setMovies)
      .catch((_) => setMovies([]));
  }, []);

// use state hook
  const [movies, setMovies] = useState<Movie[]>([]);

  return (
  // Provide to the all project: 
  // - movies an array of Movie, 
  // - updateMovies : function to update the movies list
    <MoviesContext.Provider value={{ movies, updateMovies: setMovies }}>
      <div className="App">
        <Header></Header>
        <Catalog></Catalog>
      </div>
    </MoviesContext.Provider>
  );
}

Enter fullscreen mode Exit fullscreen mode

Components

Don’t be afraid to split components into smaller components. (React Doc)

In React it's important to split the UI by components, so let's check how many components do we need :
Screenshot

As you can see, three components are standing out:

  • Header
  • Search
  • Catalog

A question to ask when creating a component:
What my component should do ?! πŸ€”

Header

The header component is pretty simple, it contains the project title and the Search component.

export const Header = () => {
  return (
    <div className="header">
      <h1 className="header__title">Movie App</h1>
      <div className="header__search">
        <Search></Search>
      </div>
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

Search

The search component should:

  1. show an input field
  2. save user search
  3. query the API with this search
  4. update the movie list

In order to save the state of our input, we will use in this component the useState hook.

export const Search = () => {
  const [search, setSearch] = useState("");
  // Consume our context to get updateMovies function
  const { updateMovies } = useContext(MoviesContext); 

  const handleOnSubmit = (event: React.FormEvent) => {
    event.preventDefault();
    if (search) {
      searchMovies(search).then((movies) => {
        updateMovies(movies);
      });
    }

  return (
    <div>
      <form name="form" onSubmit={(e) => handleOnSubmit(e)} noValidate>
        <input
          type="text"
          name="movie"
          className="search__input"
          placeholder="Search movie ... "
          value={search}
          onChange={(e) => setSearch(e.target.value)}
        />
      </form>
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

Catalog

The catalog component should:

  1. get movies from the context
  2. loop on this array
export const Catalog = () => {
  // Consume the context to get list of movies.
  const { movies } = useContext(MoviesContext);

  return (
    <div className="catalogContainer">
      {movies.map((movie) => (
        <div className="catalog__item" key={movie.id}>
          <div className="catalog__item__img">
            <img src={movie.picture || imgPlaceholder} alt={movie.title} />
            <div className="catalog__item__resume">{movie.resume}</div>
          </div>
          <div className="catalog__item__footer">
            <div className="catalog__item__footer__name">
              {movie.title} ({new Date(movie.date).getFullYear()})
            </div>
            <div className="catalog__item__footer__rating">{movie.rating}</div>
          </div>
        </div>
      ))}
    </div>
  );
};

Enter fullscreen mode Exit fullscreen mode

fetch() data from API

In order to fetch the API for data, let's create a service :

const movieApiBaseUrl = "https://api.themoviedb.org/3";

export function searchMovies(search: string): Promise<Movie[]> {
  return fetch(
    `${movieApiBaseUrl}/search/movie?query=${search}&api_key=${process.env.REACT_APP_API_KEY}`
  )
    .then((res) => res.json())
    .catch((_) => {
      return [];
    });
}

export function discoverMovies(): Promise<Movie[]> {
  return fetch(
    `${movieApiBaseUrl}/discover/movie?sort_by=popularity.desc&api_key=${process.env.REACT_APP_API_KEY}`
  )
    .then((res) => res.json())
    .then((response) => mapResult(response.results))
    .catch((_) => {
      return [];
    });
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

With this tutorial, I tried to present to you some important concept like :

  • React Context API
  • React hooks
  • function fetch to make API calls

To go further

Some more ideas to improve your skills:

  • handle No result
  • use Redux
  • pagination

Source :

  • You can clone this project on Github

Discussion

pic
Editor guide
Collapse
cayde profile image
CAYDE

Noice

Collapse
mrmetaverse profile image
Jesse

Gonna try this out! Might be a fun baseline for an XR app were building. Cheers!