In this tutorial, you’ll learn how to fetch data from an external API and display it in your app. APIs are crucial for building dynamic apps that interact with servers, databases, or other external services. Today, we will fetch real-time data and display it using the skills we’ve learned in previous lessons.
What You Will Learn Today:
- Making HTTP requests using the
fetch
API - Displaying fetched data in a list using
FlatList
- Handling loading states and error messages
- Understanding how to interact with real-world APIs
Step 1: Fetching Data from an API
React Native uses the standard JavaScript fetch
API to make HTTP requests. Let’s start by fetching data from a public API.
We’ll use a sample API, JSONPlaceholder, which provides dummy data for testing.
Modify HomeScreen.js to fetch and display a list of posts from this API.
import React, { useState, useEffect } from 'react';
import { View, Text, FlatList, ActivityIndicator, StyleSheet } from 'react-native';
export default function HomeScreen() {
const [loading, setLoading] = useState(true);
const [data, setData] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => response.json())
.then((json) => setData(json))
.catch((error) => setError(error))
.finally(() => setLoading(false));
}, []);
return (
<View style={styles.container}>
<Text style={styles.title}>Fetched Data from API</Text>
{loading ? (
<ActivityIndicator size="large" color="#6200EE" />
) : error ? (
<Text style={styles.error}>Error fetching data: {error.message}</Text>
) : (
<FlatList
data={data}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<View style={styles.listItem}>
<Text style={styles.itemTitle}>{item.title}</Text>
<Text>{item.body}</Text>
</View>
)}
/>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
backgroundColor: '#f5f5f5',
},
title: {
fontSize: 24,
marginBottom: 20,
},
listItem: {
padding: 10,
backgroundColor: '#f9c2ff',
marginVertical: 8,
borderRadius: 10,
width: '100%',
},
itemTitle: {
fontSize: 16,
fontWeight: 'bold',
},
error: {
color: 'red',
fontSize: 16,
},
});
Explanation:
- useEffect: We use the
useEffect
hook to run thefetch
request when the component mounts (only once). - fetch: This method sends a GET request to the API and retrieves a list of posts.
- ActivityIndicator: Displays a loading spinner while the data is being fetched.
- FlatList: Displays the fetched posts in a scrollable list.
Step 2: Displaying Data from the API
In the above code, once the data is fetched from the API, it is displayed in a FlatList
. The list items contain the title and body of each post.
Key Features:
- Loading State: We use the
loading
state to show a spinner while the data is being fetched. - Error Handling: If an error occurs during the fetch, we display an error message.
- Rendering List Items: Each post is rendered in a list item with its title and body.
Step 3: Displaying a Loader and Handling Errors
It’s important to handle the state of the app while the data is being fetched. We do this by displaying a loading spinner and handling any potential errors.
- Loading State: While the data is being fetched, the
ActivityIndicator
component shows a spinner to indicate that something is happening. - Error Handling: If there’s an error during the fetch, an error message is displayed.
In the code above, this is handled by:
{loading ? (
<ActivityIndicator size="large" color="#6200EE" />
) : error ? (
<Text style={styles.error}>Error fetching data: {error.message}</Text>
) : (
<FlatList
data={data}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<View style={styles.listItem}>
<Text style={styles.itemTitle}>{item.title}</Text>
<Text>{item.body}</Text>
</View>
)}
/>
)}
Explanation:
- ActivityIndicator: Shows a loading spinner when
loading
is true. - Error Message: If
error
is set, an error message is shown to the user.
Step 4: Fetching Data on Another Screen
Let’s extend this by fetching data on the DetailsScreen. We’ll modify the DetailsScreen.js to fetch details of a single post.
Modify DetailsScreen.js as follows:
import React, { useState, useEffect } from 'react';
import { View, Text, ActivityIndicator, StyleSheet } from 'react-native';
export default function DetailsScreen({ route }) {
const { postId } = route.params;
const [loading, setLoading] = useState(true);
const [post, setPost] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`)
.then((response) => response.json())
.then((json) => setPost(json))
.catch((error) => setError(error))
.finally(() => setLoading(false));
}, [postId]);
return (
<View style={styles.container}>
{loading ? (
<ActivityIndicator size="large" color="#6200EE" />
) : error ? (
<Text style={styles.error}>Error fetching post: {error.message}</Text>
) : (
<View style={styles.postContainer}>
<Text style={styles.postTitle}>{post.title}</Text>
<Text>{post.body}</Text>
</View>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
backgroundColor: '#f5f5f5',
},
postContainer: {
backgroundColor: '#fff',
padding: 20,
borderRadius: 10,
width: '100%',
},
postTitle: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 10,
},
error: {
color: 'red',
fontSize: 16,
},
});
Explanation:
- Fetching Single Post: This time, we’re fetching a single post by its ID using the API endpoint
https://jsonplaceholder.typicode.com/posts/{id}
. - useEffect Hook: The
useEffect
hook fetches the post data when thepostId
changes. - The fetched post is displayed on the DetailsScreen.
To test this, modify HomeScreen.js to pass a postId
when navigating to the DetailsScreen:
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details', { postId: item.id })}
/>
Now, clicking a button on the Home screen will navigate to the Details screen and display details about a specific post.
Step 5: Recap and Summary
Today, you learned how to fetch data from an external API and display it in your app. Here’s a quick summary of what you’ve done:
- Made an API request using the
fetch
method. - Displayed a list of data from the API using
FlatList
. - Implemented a loading state with an activity indicator.
- Handled errors by displaying error messages to the user.
- Fetched data dynamically on multiple screens.
Your app is now connected to an external data source, making it dynamic and interactive. You can now retrieve and display real-time data from an API!
Next Up: Day 7 – Managing Global State with Redux
In Day 7, we’ll introduce Redux for managing global state across different components in your app. You’ll learn how to set up Redux, create actions and reducers, and share state between different screens.
Stay tuned for more advanced state management tomorrow!