Movies

M

This tutorial teaches you to create React Native application with React Native CLI. App will load it’s data from the Movie DB. Application UI will be created with build-in React Native components and styles. Created project is tested with a emulator and a real device. To test with emulators you will need to install Android Studio or Xcode.

Purpose and learning process

In this exercise you will learn the basics of the React Native CLI development:

  • using and rendering build-in components
  • creating and rendering an own components
  • understand state and props
  • event handling
  • passing data between components
  • calling functions between components
  • using styles
  • navigating between screens
  • load and parse JSON data
  • touchable components

Example screenshots and video

Application will load data from The Movie DB and display movie based data with own components.

Look example video from here: https://youtu.be/tnKkw_Emv9s.

The Mobie DB

Sign up to The Movie DB and get the api key. Learn the basics of API and Getting Started.

You can find your API key from your profile/settings. An example request looks like this (replacing the api_key_here text with your own API key):

https://api.themoviedb.org/3/movie/76341?api_key=api_key_here

Add &append_to_response=videos to your request, if you want to include trailers to response data.

Example response will be returned with JSON data:

Now playing movies will be used in this tutorial with a following API call:

https://api.themoviedb.org/3/movie/now_playing?api_key=your_api_key&append_to_response=videos

Create a new project

Create a Movies App with React Native CLI. You can find setup instructions for Android and iOS from Native React website – Setting up the development environment. Instructions are a bit different depending on your development operating system, follow instructions and set up your system ready for React Native CLI.

When your system is ready for React Native CLI development, type a following command to create a Movies project:

npx react-native init Movies

After that you can run your app for iOS or Android:

Run instructions for iOS:
    • cd Movies && npx react-native run-ios
    - or -
    • Open Movies/ios/Movies.xcworkspace in Xcode or run "xed -b ios"
    • Hit the Run button

Run instructions for Android:
    • Have an Android emulator running (quickest way to get started), 
      or a device connected.
    • cd Movies && npx react-native run-android

For example running in Android, first start Android emulator and then give a following command:

npx react-native run-android

You might get a following “SDK location not found” error message:

SDK location not found. Define location with an ANDROID_SDK_ROOT environment 
variable or by setting the sdk.dir path in your project's local properties file 
at '/Users/USERNAME/ReactNative/Movies/android/local.properties'.

SO, you need to and on ANDROID_SDK_ROOT environment variable or create a local.properties file to your android folder in your project. You can find more nice instructions for example here: React Native Android Build Failed

Go to the android directory of your react-native project and create a file called local.properties with this line in macOS:

sdk.dir = /Users/USERNAME/Library/Android/sdk

Where USERNAME is your macOS username or in Windows (check your sdk location, might be different):

sdk.dir = C:\\Users\\USERNAME\\AppData\\Local\\Android\\sdk

You might get also error message that adb is not found, then you need to modify your path to point also to platform-tools folder where adb is.

export PATH=$PATH:~/Library/Android/sdk/platform-tools/

After you get CLI started successfully, you should see your new app running in the emulator shortly:

Modify App.js

Modify App.js code to include only needed starting code for this project. Now app will render only StatusBar and ScrollView with one Text component.

import React from 'react';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Text,
  StatusBar,
} from 'react-native';

import {
  Colors,
} from 'react-native/Libraries/NewAppScreen';

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={styles.scrollView}>
            <Text>Hello React Native CLI!</Text>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

const styles = StyleSheet.create({
  scrollView: {
    backgroundColor: Colors.lighter,
  },
});

export default App;

Double tap R with your keyboard, if emulator isn’t refresh automatically.

Load movies and show data

Read React Native Networking material to get familiar with the basic’s of Networking. Fetch is good, when data is JSON based. Of course you can use some 3th party libraries like Axios or Axios npm.

Create a new MoviesList component inside your App.js.

class MoviesList extends React.Component {
  render() {
    return (
      <Text>Test</Text>
    )
  }
}

And use it in main App.

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={styles.scrollView}>
            <MoviesList/>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

Initialize a new movies state in MoviesList component constructor.

constructor(props) {
  super(props);
  this.state = { movies: null };
} 

Start loading a data in componentDidMount event in MoviesList component:

componentDidMount(){
  this.getMovies();
}

Create a following getMovies function to your MoviesList component.

async getMovies() {
  let APIKEY = 'YOUR_API_KEY';
  let BASEURL = 'https://api.themoviedb.org/3/movie/now_playing';
  let url = BASEURL+'?api_key='+APIKEY;
  let response = await fetch(url);
  let data = await response.json();
  this.setState( {movies: data.results} );
  // check console - a movie data should be visible there
  //console.log(data.results);
}

Now movies data should be loaded and stored to movies state in MoviesList component.

Create a new MovieListItem component, which will be used to display a one movie in a list.

class MovieListItem extends React.Component {
  render() {
    return (
      <View style={styles.movieItem}>
        <Text style={styles.movieItemTitle}>{this.props.movie.title}</Text>
      </View>
    )
  }
}

Use MovieListItem component in MoviesList component rendering. map function loops through all the movies. Movie object will be send to MovieListItem component via props.

render() {
  if (this.state.movies == null){
    return(
      <View style={{flex: 1, padding: 20}}>
        <Text>Loading, please wait...</Text>
      </View>
    )
  }
  var items = this.state.movies.map(function(movie,index){
    return (
      <MovieListItem movie={movie} key={index}/>
    )
  }.bind(this));
  return (
    <ScrollView>
      {items}
    </ScrollView>
  );
}

Modify your app css-styles.

const styles = StyleSheet.create({
  scrollView: {
    backgroundColor: Colors.lighter,
  },
  movieItem: {
    margin: 5,
    flex: 1,
    flexDirection: 'row'
  },
  movieItemImage: {
    marginRight: 5
  },
  movieItemTitle: {
    fontWeight: 'bold',
  },
  movieItemText: {
    flexWrap: 'wrap'
  }
});

Double tap R in your emulator. Show titles should be visible now.

Modify MoviesListItem to display more movie data.

class MovieListItem extends React.Component {
  render() {
    let IMAGEPATH = 'http://image.tmdb.org/t/p/w500'
    let imageurl = IMAGEPATH + this.props.movie.poster_path;
    return (
      <View style={styles.movieItem}>
        <View style={styles.movieItemImage}>
          <Image source={{uri: imageurl}} style={{width: 99, height: 146}} />
        </View>
        <View style={{marginRight: 50}}>
          <Text style={styles.movieItemTitle}>{this.props.movie.title}</Text>
          <Text style={styles.movieItemText}>{this.props.movie.release_date}</Text>
          <Text numberOfLines={6} ellipsizeMode="tail" style={styles.movieItemText}>{this.props.movie.overview}</Text>
        </View> 
      </View>
    )
  }
}

Test

And now, refresh your app again and try scrolling it’s view. Image will be visible at the left and movie data in right.

Add a navigation and a movie details page

Mobile apps are rarely made up of a single screen. Managing the presentation of, and transition between, multiple screens is typically handled by what is known as a navigator.

Read more information React Navigation.

Install React Navigation to your project:

npm install @react-navigation/native @react-navigation/stack
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view

Create a new MovieListScreen.js file and copy all App.js content inside it. Modify App declaration to be a MovieListScreen component.

const MovieListScreen: () => React$Node = ({ navigation }) => {
export default MovieListScreen;

Add { navigation } to pass navigation object to MovieListScreen.

App.js need to be changed to generate a app navigation. React Navigation uses a stack navigator to manage the navigation history and presentation of the appropriate screen based on the route taken by a user inside the app. Now App only have a MovieListScreen, so it will be used, when an application is launched.

Modify App.js to include navigation.

// App.js
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

import MovieListScreen from './MovieListScreen';

const Stack = createStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="MoviesList" component={MovieListScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

Test your application. It should work the same way as without a navigation, except the navigation bar is now visible.

Create a new MovieDetailScreen.js file. This will be used to display information about selected movie from the movie list.

import React from 'react';
import {
  Text,
  View
} from 'react-native';

export default class MovieDetailScreen extends React.Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>MovieDetailScreen</Text>
      </View>
    )
  }
}

Modify App.js to include navigation to this MovieDetailScreen.

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

import MovieListScreen from './MovieListScreen';
import MovieDetailScreen from './MovieDetailScreen';

const Stack = createStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="MoviesList" component={MovieListScreen} />
        <Stack.Screen name="MovieDetails" component={MovieDetailScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

Modify MovieListItems creation in a MoviesList rendering. Add TouchableHighlight around MovieListItem to handle a tap gesture.

var items = this.state.movies.map(function(movie,index){
  return (
    <TouchableHighlight onPress={_ => this.itemPressed(index)} 
                    underlayColor="lightgray" key={index}>
      <MovieListItem movie={movie} key={index}/>
    </TouchableHighlight>
  )
}.bind(this));

Remember add import to TouchableHighlight and create a itemPressed function.

Add itemPressed function:

itemPressed = (index) => {
  alert(index);
}

Double tap R in your emulator and click one of the movie rows. You should see Alert and row number.

Add navigation to MovieDetail page. Remove alert(index) line and add navigation to MovieDetail screen:

itemPressed = (index) => {
  this.props.navigation.navigate('MovieDetails');
}

Now above code is in the child component (MoviesList) and you can’t use navigation from there without sending it from the parent component. So, you need to modify MovieListScreen class to pass navigation as a props.

Modify MovieListScreen render to pass a main navigation to MoviesList child component via props.

...
<MovieList navigation={ navigation }/>
...

Now test your app and you should can move between main and detail screens. Of course MovieDetail screen is still blank.

Read more about navigation here: React Navigation.

Show movie details in MovieDetailScreen

You can pass a parameters to the new screen, when you are using a navigation. Modify itemPressed function to send selected movie data to the MovieDetail screen.

itemPressed = (index) => {
    this.props.navigation.navigate(
      'MovieDetails', 
      { movie: this.state.movies[index] }
    );
}

Modify MovieDetailScreen to show movie details. route object will be passed here via props and it will be used to get movie data from navigation parameters. Component will render movie poster with Image component and a few data with Text component.

import React from 'react';
import { Text, View, Image, StyleSheet } from 'react-native';

export default class MovieDetailScreen extends React.Component {

  render() {
    const { route } = this.props;
    const { movie } = route.params; 
    let IMAGEPATH = 'http://image.tmdb.org/t/p/w500';
    let imageurl = IMAGEPATH + movie.backdrop_path;

    return (
      <View>
          <Image source={{uri: imageurl}} style={styles.image}  />
          <Text style={styles.title}>{movie.title}</Text>
          <Text style={styles.text}>{movie.release_date}</Text>
          <Text style={styles.text}>{movie.overview}</Text>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  image: {
    aspectRatio: 670/250
  },
  title: {
    fontWeight: 'bold',
    fontSize: 15
  },
  text: {
    fontSize: 12,
    flexWrap: 'wrap'
  }
});

TEst

Your application should work now.

Add comment

Pasi Manninen

Pasi Manninen

Pasi is a mobile and web application developer. Currently working as a senior lecturer in JAMK University of Applied Sciences. Pasi has programming experience over many decades and has taught dozens of courses since the 90's.

Recent Posts

Follow Me