November 21, 2024
Day 12 — Rendering Dynamic Lists in React Native with Live API Data
Introduction: On Day 12 of my React Native journey, I combined everything I’ve learned so far — list rendering, state management, and API…

By krishna chaitanya
2 min read
Introduction: On Day 12 of my React Native journey, I combined everything I've learned so far — list rendering, state management, and API integration — to create a dynamic, data-driven app. Displaying data from an API in a list format is a common requirement for modern mobile apps, such as social feeds, product catalogs, and more.
Project: Dynamic API-Driven User List
For today's practice, I built a simple app that fetches user data from an API and displays it in a scrollable list. I used:
FlatList: For rendering the user data efficiently.fetch: To retrieve the data from a live API.- Loading Indicators: To improve user experience while fetching data.
Step 1: Fetching Data from an API
I used the free JSONPlaceholder API to fetch user data.
const fetchUsers = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
return response.json();
};const fetchUsers = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
return response.json();
};Step 2: Displaying Data with FlatList
Here's the complete implementation:
import React, { useEffect, useState } from 'react';
import {
View,
Text,
FlatList,
ActivityIndicator,
StyleSheet,
} from 'react-native';
const UserList = () => {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchUsers = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await response.json();
setUsers(data);
} catch (error) {
console.error('Error fetching users:', error);
} finally {
setLoading(false);
}
};
fetchUsers();
}, []);
const renderUser = ({ item }) => (
<View style={styles.userCard}>
<Text style={styles.userName}>{item.name}</Text>
<Text style={styles.userEmail}>{item.email}</Text>
<Text style={styles.userPhone}>📞 {item.phone}</Text>
</View>
);
if (loading) {
return <ActivityIndicator size="large" style={styles.loader} />;
}
return (
<FlatList
data={users}
keyExtractor={(item) => item.id.toString()}
renderItem={renderUser}
contentContainerStyle={styles.listContainer}
/>
);
};
const styles = StyleSheet.create({
loader: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
listContainer: {
padding: 10,
},
userCard: {
backgroundColor: '#e0f7fa',
padding: 15,
marginVertical: 8,
borderRadius: 8,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 2,
},
userName: {
fontSize: 18,
fontWeight: 'bold',
},
userEmail: {
fontSize: 16,
color: '#555',
},
userPhone: {
fontSize: 14,
color: '#888',
marginTop: 5,
},
});
export default UserList;import React, { useEffect, useState } from 'react';
import {
View,
Text,
FlatList,
ActivityIndicator,
StyleSheet,
} from 'react-native';
const UserList = () => {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchUsers = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await response.json();
setUsers(data);
} catch (error) {
console.error('Error fetching users:', error);
} finally {
setLoading(false);
}
};
fetchUsers();
}, []);
const renderUser = ({ item }) => (
<View style={styles.userCard}>
<Text style={styles.userName}>{item.name}</Text>
<Text style={styles.userEmail}>{item.email}</Text>
<Text style={styles.userPhone}>📞 {item.phone}</Text>
</View>
);
if (loading) {
return <ActivityIndicator size="large" style={styles.loader} />;
}
return (
<FlatList
data={users}
keyExtractor={(item) => item.id.toString()}
renderItem={renderUser}
contentContainerStyle={styles.listContainer}
/>
);
};
const styles = StyleSheet.create({
loader: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
listContainer: {
padding: 10,
},
userCard: {
backgroundColor: '#e0f7fa',
padding: 15,
marginVertical: 8,
borderRadius: 8,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 2,
},
userName: {
fontSize: 18,
fontWeight: 'bold',
},
userEmail: {
fontSize: 16,
color: '#555',
},
userPhone: {
fontSize: 14,
color: '#888',
marginTop: 5,
},
});
export default UserList;Key Features of the User List
Fetching Data:
- The
fetchUsersfunction retrieves user data from the API. - Data is stored in the
usersstate usinguseState.
- Loading Indicator:
- While fetching data, an
ActivityIndicatorprovides visual feedback. - The
loadingstate toggles the display of the loader and the list.
Efficient Rendering with FlatList:
refreshing: Manages the refresh state.onRefresh: Defines the logic to refetch data when the user pulls down.
const [refreshing, setRefreshing] = useState(false);
const handleRefresh = async () => {
setRefreshing(true);
await fetchUsers();
setRefreshing(false);
};
return (
<FlatList
data={users}
keyExtractor={(item) => item.id.toString()}
renderItem={renderUser}
contentContainerStyle={styles.listContainer}
refreshing={refreshing}
onRefresh={handleRefresh}
/>
);
const [refreshing, setRefreshing] = useState(false);
const handleRefresh = async () => {
setRefreshing(true);
await fetchUsers();
setRefreshing(false);
};
return (
<FlatList
data={users}
keyExtractor={(item) => item.id.toString()}
renderItem={renderUser}
contentContainerStyle={styles.listContainer}
refreshing={refreshing}
onRefresh={handleRefresh}
/>
);
Features:
refreshing: Manages the refresh state.onRefresh: Defines the logic to refetch data when the user pulls down.
What I Learned Today
Fetching Data:
- Use
fetchto retrieve data from an API. - Handle errors gracefully to ensure the app remains robust.
- FlatList for Rendering:
- Efficiently render lists of dynamic data.
- Customize list items with styles and layout.
Loading Indicators:
. Improve UX by showing an activity indicator while waiting for data.Enhance interactivity with refreshing functionality.
Reflections on Day 12
Building a dynamic list with live API data was incredibly rewarding. It was satisfying to see data fetched from an external server and displayed in a well-styled, scrollable list. These concepts are foundational for building apps that interact with real-world data.
What's Next? Tomorrow, I'll tackle Handling User Input and Forms, focusing on multi-step forms and advanced validation techniques to create robust data entry flows.