After receiving data from a REST API, a React Native application needs to display that data on the screen. In this lesson, we will learn how to fetch JSON data from a PHP REST API and display it using React Native components such as Text, View, FlatList, and ScrollView.
API data is information returned by the server. REST APIs commonly return this information in JSON format.
{
"success": true,
"data": [
{
"id": 1,
"name": "Rahul"
},
{
"id": 2,
"name": "Amit"
}
]
}
React Native
↓
fetch()
↓
PHP API
↓
MySQL
↓
JSON
↓
response.json()
↓
React Native State
↓
UI Screen
useState can store the data received from the API.
const [students, setStudents] =
useState([]);
An empty array is useful when the API will return a list of records.
const response = await fetch(
API_URL
);
const result =
await response.json();
console.log(result);
The response is converted from JSON into a JavaScript object.
const result =
await response.json();
setStudents(
result.data || []
);
Once the state changes, React Native re-renders the screen.
If the API returns one object, individual properties can be displayed using Text.
const [student, setStudent] =
useState(null);
<Text>
{student?.name}
</Text>
<Text>
Name: {student?.name}
</Text>
<Text>
Email: {student?.email}
</Text>
<Text>
Course: {student?.course}
</Text>
The optional chaining operator helps prevent errors when student is initially null.
When the API returns many records, FlatList is commonly used.
<FlatList
data={students}
renderItem={({ item }) => (
<Text>
{item.name}
</Text>
)}
/>
keyExtractor provides a stable key for each item in a FlatList.
<FlatList
data={students}
keyExtractor={item =>
item.id.toString()
}
renderItem={({ item }) => (
<Text>
{item.name}
</Text>
)}
/>
<View>
<Text>
Name: {item.name}
</Text>
<Text>
Email: {item.email}
</Text>
</View>
View can be used to group related information.
renderItem={({ item }) => (
<View>
<Text>
{item.name}
</Text>
<Text>
{item.email}
</Text>
<Text>
{item.course}
</Text>
</View>
)}
This approach can be styled later to create a professional student card.
useEffect(() => {
loadStudents();
}, []);
The empty dependency array means the function runs when the component is initially mounted.
async function loadStudents() {
setLoading(true);
setError("");
try {
const response =
await fetch(API_URL);
const result =
await response.json();
if (!response.ok) {
throw new Error(
result.message ||
"Unable to load students"
);
}
setStudents(
result.data || []
);
} catch (error) {
setError(
error.message
);
} finally {
setLoading(false);
}
}
if (loading) {
return (
<View>
<ActivityIndicator
size="large"
/>
<Text>
Loading students...
</Text>
</View>
);
}
if (error) {
return (
<View>
<Text>
{error}
</Text>
</View>
);
}
Showing an error message is better than leaving the user with a blank screen.
{students.length === 0 ? (
<Text>
No students found.
</Text>
) : (
<FlatList
data={students}
renderItem={renderStudent}
/>
)}
ScrollView can be used for a smaller amount of data.
<ScrollView>
{students.map(student => (
<View key={student.id}>
<Text>
{student.name}
</Text>
<Text>
{student.email}
</Text>
</View>
))}
</ScrollView>
FlatList is generally preferred for long lists because it is designed for efficient list rendering.
API responses can contain nested objects.
{
"id": 1,
"name": "Rahul",
"course": {
"id": 5,
"name": "React Native"
}
}
React Native can access the nested property:
<Text>
{student.course?.name}
</Text>
{student?.name ? (
<Text>
Student: {student.name}
</Text>
) : (
<Text>
Student information unavailable.
</Text>
)}
Conditional rendering lets the application display different content depending on the available API data.
After adding, updating, or deleting a record, the list can be refreshed.
async function refreshData() {
await loadStudents();
}
Another option is to update the local state immediately after a successful CRUD operation.
const result =
await response.json();
if (result.success) {
setStudents([
result.data,
...students
]);
}
This can add a newly created record to the beginning of an existing list.
setStudents(
students.map(student =>
student.id === updatedStudent.id
? updatedStudent
: student
)
);
This updates the matching record in the local React Native state.
setStudents(
students.filter(
student =>
student.id !== deletedId
)
);
The deleted record is removed from the displayed list.
<FlatList
data={students}
keyExtractor={item =>
item.id.toString()
}
renderItem={({ item }) => (
<View>
<Text>
Name: {item.name}
</Text>
<Text>
Email: {item.email}
</Text>
<Text>
Course: {item.course}
</Text>
</View>
)}
ListEmptyComponent={
<Text>
No students found.
</Text>
}
/>
if (loading) {
return (
<ActivityIndicator
size="large"
/>
);
}
if (error) {
return (
<Text>
{error}
</Text>
);
}
return (
<FlatList
data={students}
renderItem={renderStudent}
/>
);
In a TypeScript React Native project, an interface can describe the API data structure.
interface Student {
id: number;
name: string;
email: string;
course: string;
}
const [students, setStudents] =
useState<Student[]>([]);
TypeScript helps detect incorrect property names and data types.
function StudentCard({
student
}) {
return (
<View>
<Text>
{student.name}
</Text>
<Text>
{student.email}
</Text>
<Text>
{student.course}
</Text>
</View>
);
}
Reusable components make large React Native applications easier to maintain.
import React, {
useEffect,
useState
} from "react";
import {
View,
Text,
FlatList,
ActivityIndicator
} from "react-native";
const API_URL =
"https://example.com/api/students.php";
export default function StudentList() {
const [students, setStudents] =
useState([]);
const [loading, setLoading] =
useState(false);
const [error, setError] =
useState("");
async function loadStudents() {
setLoading(true);
setError("");
try {
const response =
await fetch(API_URL);
const result =
await response.json();
if (!response.ok) {
throw new Error(
result.message ||
"Unable to load students"
);
}
if (!result.success) {
throw new Error(
result.message ||
"API request failed"
);
}
setStudents(
result.data || []
);
} catch (error) {
setError(
error.message
);
} finally {
setLoading(false);
}
}
useEffect(() => {
loadStudents();
}, []);
if (loading) {
return (
<View>
<ActivityIndicator
size="large"
/>
<Text>
Loading students...
</Text>
</View>
);
}
if (error) {
return (
<View>
<Text>
{error}
</Text>
</View>
);
}
return (
<FlatList
data={students}
keyExtractor={item =>
item.id.toString()
}
renderItem={({ item }) => (
<View>
<Text>
Name: {item.name}
</Text>
<Text>
Email: {item.email}
</Text>
<Text>
Course: {item.course}
</Text>
</View>
)}
ListEmptyComponent={
<Text>
No students found.
</Text>
}
/>
);
}
React Native Screen
↓
useEffect()
↓
fetch()
↓
PHP API
↓
JSON Data
↓
response.json()
↓
setState()
↓
React Re-render
↓
┌──────┴───────┐
↓ ↓
Single Object Array Data
↓ ↓
View FlatList
↓ ↓
Display Data
↓
User Interface
This is the basic process used to display REST API data in React Native applications.
Question: Which React Native component is commonly used to efficiently display a list of API records?