Moses Esan
Aug 21 · Unlisted

Before continuing, make sure you have gone through the previous tutorials and created a sample module and an authentication module.

Part 1, Part 2, Part 3, Part 4

Demo
Make sure you are in the project root$ npm i --save react-native-snap-carousel react-native-fade-in-image expo-linear-gradient moment react-native-read-more-text react-native-webview$ cd app/modules && mkdir movies && cd movies && mkdir components scenes && touch index.js constants.js api.js reducer.js utils.js

Step 1: Constants

In the constants file, the API endpoints, redux action types, app section and movie genres are declared.

modules/movies/constants.js

Step 2: Create API

This functions declared in this file will interact with the backend API. For this tutorial, I am using The Movie Database (TMDb) API, an API key is needed, you can get one by signing up.

getData: Returns a promise, its callback function uses the axios.all function to make multiple concurrent requests to the api to retrieve the most popular, top rated, now playing and upcoming movies.

If successful the result is extracted and a new data variable is created and the promise is resolved with this data. If an error occurs, the promise is rejected with the error object.

export function getData() {
return new Promise((resolve, reject) => {
let requests = [
axios.get(c.POPULAR),
axios.get(c.TOP_RATED),
axios.get(c.NOW_PLAYING),
axios.get(c.UPCOMING)
];

axios.all(requests)
.then(axios.spread((popular, top_rated, now_playing, upcoming) => {
popular = popular.data.results;
top_rated = top_rated.data.results;
now_playing = now_playing.data.results;
upcoming = upcoming.data.results;

let data = {popular, top_rated, now_playing, upcoming};
resolve(data);
}))
.catch(error => reject(handleError(error)));
});
};

getMoviesByGenre: Returns a promise, takes in a genre id and makes an api call to retrieve all movies in that genre. Resolves with returned data.

export function getMoviesByGenre(genre_id) {
return new Promise((resolve, reject) => {
axios.get(c.DISCOVER + "&with_genres=" + genre_id)
.then(res => res.data)
.then((data) => resolve(data))
.catch(error => reject(handleError(error)));
});
}

getMovieDetails: Returns a promise, takes in a genre id and uses the axios.all function to make multiple concurrent requests to the api to retrieve the movie’s details including videos and images, credits and similar movies.

If successfully the result is extracted and a new data variable is created and the promise is resolved with this data. If an error occurs, the promise is rejected with the error object.

export function getMoviesDetails(movie_id) {
return new Promise((resolve, reject) => {

let requests = [
axios.get(c.MOVIE_DETAILS + movie_id + c.API_KEY + c.API_PARAMS),
axios.get(c.MOVIE_DETAILS + movie_id + c.CREDITS),
axios.get(c.MOVIE_DETAILS + movie_id + c.SIMILAR)
];
axios.all(requests)
.then(axios.spread((details, casts, similar) => {
details = details.data;
casts = casts.data;
similar = similar.data.results;

let data = {...details, ...casts, similar};
resolve(data);
}))
.catch(error => reject(handleError(error)));
});
};

The handleError function is in charge of returning the appropriate error message.

function handleError(error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
let {data} = error.response;
error = data.error;
}

if (error.hasOwnProperty("message")) error = error.message;

return error;
};

Paste this functions into the api.js file, don’t forget to import the constants file and the axios package.

Step 3: Create Reducer

The reducer file will handle the “DATA_AVAILABLE” action.

For better understanding, here’s a sample of the action object passed to the reducer.

{
"type": c.DATA_AVAILABLE,
"data": {
popular: [{...}, ...],
top_rated: [{...}, ...],
upcoming: [{...}, ...],
now_playing: [{...}, ...]
}
}
app/modules/movies/reducer.js

Root Reducer
Add the module reducer to the rootReducer.js file.

app/redux/rootReducer.js....import moviesReducer from "../modules/movies/reducer.js"const rootReducer = combineReducers({ homeReducer, authReducer, moviesReducer });

Step 4: Create Components and Scenes

Components

Make sure you are in the project root$ cd app/modules/movies/components
$ touch Spotlight.js Panel.js Featured.js Filters.js MovieItem.js MovieInfo.js Synopsis.js Rating.js

Spotlight: Uses the react-native-snap-carousel to display a carousel of all the top 10 popular movies. The Spotlight component uses the SpotlightItem, also declared in this file.

Spotlight

Panel: Uses a scrollview to display a list of movies. This component uses the PanelItem also declared in this file.

Panel and PanelItem

Featured: Used for displaying a movie and its details, users can tap to view trailer.

Featured

Filters: Used for displaying the genres available. User can type to view all movies in a specific genre.

Filters

MovieItem: Used by the Flatlist for displaying a movie and its details.

MovieItem

MovieInfo and Rating: Used in the Movie scene.

MovieInfo and Rating

Video: Used in the Movie scene. Created in Panel.js

VideoItem

Synopsis: Used in the Movie scene.

Synopsis

Components files can be found in the repo — Movies Module Components

Scenes

Make sure you are in the project root$ cd app/modules/movies/scenes
$ touch Discover.js Movies.js Movie.js Trailers.js

Discover: This scene will display 1 Spotlight, 3 Panels and 2 Featured components. The spotlight will use the popular movies data. The 3 panels will display the top rated, now playing and upcoming movies. The featured components will display a random movie from the top rated and now playing data.

The api getData function is called to retrieve the data, if successful, a redux action is created with the type DATA_AVAILABLE and dispatched to the reducer.

app/modules/movies/scenes/Discover.js

Movies: This scene will display a list of movies in a specific genre. It calls the getMoviesByGenre api function , the genre id retrieved from the props is passed as a parameter. In this scene, redux will not be used instead the data will be saved in the components state using useState hook.

app/modules/movies/scenes/Movies.js

Trailers: This scene will display the trailer for a movie from Youtube using a WebView. The getMovieDetails function is called to retrieve the movie details including its videos. If successful, the first video is taken and the youtube link is constructed using the video id.

app/modules/movies/scenes/Trailers.js

Movie: This scene will display the information for a particular movie, this includes synopsis, cast, crew and videos available.

app/modules/movies/scenes/Movie.js

Module Index
The module index file is the entry point into the module, the module’s routes stack is created using React Navigation createStackNavigator function. The routes stack is created and exported.

import {createStackNavigator} from 'react-navigation';

import Discover from "./scenes/Discover"
import
Movies from "./scenes/Movies"
import
Movie from "./scenes/Movie"
import
Trailers from "./scenes/Trailers"

const
RouteStack = createStackNavigator({
Discover,
Movies,
Movie,
Trailers
});

export default RouteStack;

Step 5: Update Apps Routes Stack

In the index.js file, import the movies routes stack and add it to the apps main routes stack. Replace the previously created home stack with the movies stack.

app/index.js

Run the command below to test the app.

$ expo start

Optional: Search

Take it one step further by adding a Search scene.

API

export function searchMovies(keyword) {
return new Promise((resolve, reject) => {
axios.get(c.SEARCH + "&query=" + keyword)
.then(res => res.data)
.then((data) => resolve(data))
.catch((error) => reject(handleError(error)));
});
}

Scene

Create a scene with a Flatlist that reuses the MovieItem component to display the search results.

That’s all folks!

Related Tutorials

  1. How to Build a React Native App Using React Hooks and Redux — Getting Started Boilerplate
  2. How to Build a React Native App Using React Hooks and Redux — Create “Modules”
  3. How to Build a React Native App Using React Hooks and Redux — Authentication Module
  4. Tutorial 1: React Native Redux Boilerplate
  5. Tutorial 2: React Native Redux with CRUD operations

Other Tutorials

  1. Tutorial 4: How to Build a Laravel 5.4 JWT-Powered Mobile App Authentication API
  2. Tutorial 5: How to Build a Laravel 5.4 JWT Authentication API with E-Mail Verification
  3. Tutorial 6 & 7: How to Build a Laravel 5.4 Administration Module with Role-based permissions using Entrust package

Mesan Digital

Sharing tutorials on the development of React Native and PHP projects.

Unlisted

Moses Esan

Written by

Full Stack Developer

Mesan Digital

Sharing tutorials on the development of React Native and PHP projects.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade