React Tutorial: Movie App 🎬

maj07

Majuran SIVAKUMAR

Posted on October 30, 2020

React Tutorial: Movie App 🎬

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="catalogitemimg">
<img src={movie.picture || imgPlaceholder} alt={movie.title} />
<div className="catalogitemresume">{movie.resume}</div>
</div>
<div className="catalogitemfooter">
<div className="catalogitemfootername">
{movie.title} ({new Date(movie.date).getFullYear()})
</div>
<div className="catalogitemfooter_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(
</span><span class="p">${</span><span class="nx">movieApiBaseUrl</span><span class="p">}</span><span class="s2">/search/movie?query=</span><span class="p">${</span><span class="nx">search</span><span class="p">}</span><span class="s2">&amp;api_key=</span><span class="p">${</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">REACT_APP_API_KEY</span><span class="p">}</span><span class="s2">
)
.then((res) => res.json())
.catch((_) => {
return [];
});
}

export function discoverMovies(): Promise<Movie[]> {
return fetch(
</span><span class="p">${</span><span class="nx">movieApiBaseUrl</span><span class="p">}</span><span class="s2">/discover/movie?sort_by=popularity.desc&amp;api_key=</span><span class="p">${</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">REACT_APP_API_KEY</span><span class="p">}</span><span class="s2">
)
.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
πŸ’– πŸ’ͺ πŸ™… 🚩
maj07
Majuran SIVAKUMAR

Posted on October 30, 2020

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

Sign up to receive the latest update from our blog.

Related