Hi everyone. In the last chapter, we discussed how to fetch data from API. In this article we are going to learn about React Native FlatList.

We created an app and we checked the json formatted data in the browser. But in that app, we didn’t see anything in the front-end. We just saw data in the console. There wasn’t any beautiful UI with fetched data.

In this chapter, we are going to continue the app which we paused last chapter and create a beautiful UI with fetched data.

We already have fetched data into the console. Now, it’s time to show them in the UI. For that, we need to put those data in list format. To show a list in React Native, we have several components such as ListView, SectionList or React Native FlatList. Although, these all are used for showing a list, each of these has their differences. React Native FlatList which we are going to discuss in this article, has more advantages and quite easy and simple according to the experience I have had.

What is React Native FlatList?

Normally, React Native View element doesn’t support scrolling. For that, React Native has defined another element named ‘ScrollView’. But it is only for scrolling and it doesn’t have any facility to create a list format. React Native FlatList helps us to display a scrolling list of structured data. Unlike ScrollView, React Native FlatList supports for long lists of data and it only renders the elements which are currently shown on the screen. It doesn’t render all the elements at once.

Defining State

First of all, we have to define the state and inside state, define an empty array value named ‘package’ in DataList.js file.

constructor(props) {
    super(props);

    this.state = {
      package: []
    };
  }

In the last article, we just added console.log code as the response of fetched data. Now, we are going to assign those fetched data to the state array which we just defined.

fetchMovies() {
    fetch('https://5cc814182dcd9d0014768ba9.mockapi.io/movies')
      .then((response) => response.json())
      .then((responseJson) => {
        this.setState({ package: responseJson });
      }).catch((error) => {
        console.log("Data fetching failed");
      });
  }

Using React Native FlatList in our app

Now, we have assigned fetched data values to the state array. Now we import FlatList from react-native library.

import { View, FlatList } from 'react-native';

Then, we add React Native FlatList element into return method.

<FlatList
 data={this.state.package}
 renderItem={React Native element format}
/>

The React Native FlatList component has two main properties named data and renderItem. ‘data’ property is the source of information for the list we are creating. ‘renderItem’ property is for returning a formatted component.

Creating a component to format elements

Formatted component means React Native FlatList need to return data with a beautiful UI. It’s useless if it only returns a plain text. Therefore we need to define a React Native element format inside a method and call it in renderItem property in FlatList.

For data property, we assign state array value.

Let’s define element format inside a method and call it.

renderListItem = ({ item }) => (
    <View>
      <View style={{ width: '20%', height: 70, justifyContent: 'center', alignItems: 'center' }}>
        <Text>{item.name}</Text>
      </View>
    </View>
  )

We have defined the method as above mentioned and defined a React Native element structure. When we accessed data of state using data property of React Native FlatList and then call this method in renderItem, it allows us to access those data in state using ‘item’ object in this method. As you can see, I have access the name property in the API using ‘item.name’. Other values also can be accessed like that. Now We have to call this method in React Native FlatList element.

<FlatList
 data={this.state.package}
 renderItem={this.renderListItem} 
/>

Now we have called the method in renderItem property. Let’s reload our app.

React Native FlatList - Fetched data

Getting rid of warnings

As you can see, we have successfully displayed data on the screen. You can see the list of names from the API. But you can see two warnings on the screen.  You don’t have to worry about second warning because it says we have opened remote debugger. That’s nothing to concern at the moment because we still need that debugger. But the first warning says “VirtualizedList: missing keys for items, make sure to specify a key property on each item or provide a custom keyExtractor”. 

It says we need to define a key to access these data in the API. We have a primary key in API data called ‘id’. We have to give that id to elements we defined, in renderListItem method. Here is how we do that.

renderListItem = ({ item }) => (
    <View key={item.id}>
      <View style={{ width: '20%', height: 70, justifyContent: 'center', alignItems: 'center' }}>
        <Text>{item.name}</Text>
      </View>
    </View>
  )

Now we have to access that ‘id’ inside React Native FlatList element as well. We do that using keyExtractor property of React Native FlatList. That property expects a string value. But id is a integer. So, we have to convert it to string when we pass id value to that property. If we don’t convert it, app will give us another warning to convert it.

<FlatList
 data={this.state.package}
 renderItem={this.renderListItem}
 keyExtractor={(item, index) => item.id.toString()}
/>

Let’s reload the app again.

React Native FlatList - Without warning

Now you can see, that warning is gone. We still have one warning. We can get rid of that when we turn off the debugger.

So, hard part is over. Now we just have to access other data as well just like we accessed data before and show them on the screen and style them.

Adding more elements

I am going to add more elements to renderListItem method to access other data in state.

renderListItem = ({ item }) => (
    <View key={item.id}>
      <View style={{ width: '100%', height: 40, justifyContent: 'center', alignItems: 'center' }}>
        <Text style={{ fontSize: 20, color: '#000' }}>{item.name}</Text>
      </View>
      <View style={{ width: '100%', height: 500, justifyContent: 'center', alignItems: 'center' }}>
        <Image style={{ width: '100%', height: '100%' }} source={{ uri: item.image }} />
      </View>
    </View>
  )

Now reload the app again.

React Native FlatList - pretty UI

As you can see, we get a beautiful UI. You can scroll down if you want to see other data we fetched. Now I want another thing to happen. This mobile app is about giving uus details of movies. We put the movie name on the top. Then, we put the movie image. Finally, I need a button at the bottom of the image and that button should navigate us to a website which has more details about the movie. Those website url is given in API.

Creating a button

To create a button, I am going to import TouchableOpacity from react native library.

import { View, FlatList, Image, Text, TouchableOpacity } from 'react-native';

Now, let’s create a button inside renderListItem method.

  renderListItem = ({ item }) => (
    <View key={item.id}>
      <View style={{ width: '100%', height: 40, justifyContent: 'center', alignItems: 'center' }}>
        <Text style={{ fontSize: 20, color: '#000' }}>{item.name}</Text>
      </View>
      <View style={{ width: '100%', height: 500, justifyContent: 'center', alignItems: 'center' }}>
        <Image style={{ width: '100%', height: '100%' }} source={{ uri: item.image }} />
      </View>
      <TouchableOpacity style={{ flex: 1, alignSelf: 'stretch', backgroundColor: '#fff', borderRadius: 5, borderWidth: 2, borderColor: '#007aff', marginLeft: 5, marginRight: 5 }}>
        <Text style={{ alignSelf: 'center', color: '#007aff', fontSize: 16, fontWeight: '600', paddingTop: 10, paddingBottom: 10 }}>
          Details
          </Text>
      </TouchableOpacity>
    </View>
  )

Run the app again.

React Native FlatList - UI with button

Linking the button

As you can see, we have added a button as well. But this button doesn’t do anything. We have to give it a task. As I mentioned before, it should navigate to a website when the button is pressed. So, we have to link this button to the website. For that, there is another thing called ‘Linking’ to be imported from react native library. Let’s import it now.

import { View, FlatList, Image, Text, TouchableOpacity, Linking } from 'react-native';

This ‘Linking’ helps us to open an URL when a button is pressed. Now, we should add this to the button.

renderListItem = ({ item }) => (
    <View key={item.id}>
      <View style={{ width: '100%', height: 40, justifyContent: 'center', alignItems: 'center' }}>
        <Text style={{ fontSize: 20, color: '#000' }}>{item.name}</Text>
      </View>
      <View style={{ width: '100%', height: 500, justifyContent: 'center', alignItems: 'center' }}>
        <Image style={{ width: '100%', height: '100%' }} source={{ uri: item.image }} />
      </View>
      <TouchableOpacity onPress={() => Linking.openURL(item.url)} style={{ flex: 1, alignSelf: 'stretch', backgroundColor: '#fff', borderRadius: 5, borderWidth: 2, borderColor: '#007aff', marginLeft: 5, marginRight: 5 }}>
        <Text style={{ alignSelf: 'center', color: '#007aff', fontSize: 16, fontWeight: '600', paddingTop: 10, paddingBottom: 10 }}>
          Details
          </Text>
      </TouchableOpacity>
    </View>
  )

As you can see, we added onPress property to the button and then we asked it to open the URL given if the button is pressed.

Okay!!!

Let’s run our app again.

React Native FlatList - Final UI

This our final UI. Now you can press the button and navigate to a website which has more details about the movie.

Now you have the knowledge about listing data fetched from API with React Native FlatList and listing them in a formatted component. In addition to that, you have gained knowledge linking a button.

Now we have finished our app. You can add more features if you want.

Complete code of the session

This is the whole code of DataList.js file.

import React, { Component } from 'react';
import { View, FlatList, Image, Text, TouchableOpacity, Linking } from 'react-native';

class DataList extends Component {

  constructor(props) {
    super(props);

    this.state = {
      package: []
    };
  }

  fetchMovies() {
    fetch('https://5cc814182dcd9d0014768ba9.mockapi.io/movies')
      .then((response) => response.json())
      .then((responseJson) => {
        this.setState({ package: responseJson });
      }).catch((error) => {
        console.log("Data fetching failed");
      });
  }

  componentWillMount() {
    this.fetchMovies();
  }

  renderListItem = ({ item }) => (
    <View key={item.id}>
      <View style={{ width: '100%', height: 40, justifyContent: 'center', alignItems: 'center' }}>
        <Text style={{ fontSize: 20, color: '#000' }}>{item.name}</Text>
      </View>
      <View style={{ width: '100%', height: 500, justifyContent: 'center', alignItems: 'center' }}>
        <Image style={{ width: '100%', height: '100%' }} source={{ uri: item.image }} />
      </View>
      <TouchableOpacity onPress={() => Linking.openURL(item.url)} style={{ flex: 1, alignSelf: 'stretch', backgroundColor: '#fff', borderRadius: 5, borderWidth: 2, borderColor: '#007aff', marginLeft: 5, marginRight: 5 }}>
        <Text style={{ alignSelf: 'center', color: '#007aff', fontSize: 16, fontWeight: '600', paddingTop: 10, paddingBottom: 10 }}>
          Details
          </Text>
      </TouchableOpacity>
    </View>
  )

  render() {
    return (
      <View>
        <FlatList
         data={this.state.package}
         renderItem={this.renderListItem}
         keyExtractor={(item, index) => item.id.toString()}
        />
      </View>
    );
  }
}

export default DataList;

Let’s meet again with more react native features to learn in the next article.

Thank you.