Building a polished mobile app often involves incorporating user-friendly
features like sticky headers and search functionality. In this tutorial, we'll
explore how to achieve this using React Native's
FlatList
component along with the
react-native-elements
library for its convenient pre-built
components.
We'll be crafting an app that displays a list of users fetched from an API. The key features we'll implement are:
- Sticky Header: A header containing a search bar that remains fixed at the top even as the user scrolls through the list.
- Live Search: A search bar that filters the user list in real-time based on the entered text.
This approach ensures users can easily search and navigate through the data, enhancing the overall user experience.
1. Project Setup
First, make sure you have a React Native project set up. If not, you can create one following the instructions here: https://reactnative.dev/docs/environment-setup.
Next, install the react-native-elements
library, which provides
us with a nice pre-built SearchBar
component:
npm install react-native-elements
2. Building the App
Let's dive into the code:
import React, { useState, useEffect } from 'react';
import {
Platform,
StatusBar,
SafeAreaView,
View,
FlatList,
StyleSheet,
Text
} from 'react-native';
import { SearchBar } from 'react-native-elements';
const App = () => {
// Function to structure data for FlatList with header and search bar
const generateListData = (users) => {
return [
{
type: 'title',
text: 'Users'
},
{
type: 'search-bar'
},
...users.map(user => ({ type: 'user', id: user.id, user }))
];
};
const [users, setUsers] = useState([]); // Stores all fetched users
const [listData, setListData] = useState(generateListData([])); // Manages data displayed in FlatList
const [searchTerm, setSearchTerm] = useState(''); // Tracks search bar input
useEffect(() => {
// Fetch user data on component mount
const fetchData = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await response.json();
setUsers(data);
setListData(generateListData(data)); // Initialize listData with fetched users
} catch (error) {
console.error("Error fetching data:", error);
}
};
fetchData();
}, []);
// Handle changes in the search bar input
const handleSearch = (text) => {
setSearchTerm(text);
const filtered = users.filter((user) =>
user.name.toLowerCase().includes(text.toLowerCase())
);
setListData(generateListData(filtered)); // Update listData with filtered results
};
// Render each item based on its type
const renderItem = ({ item }) => {
switch (item.type) {
case 'title':
return <Text style={styles.title}>{item.text}</Text>;
case 'search-bar':
return (
<SearchBar
placeholder="Search users..."
onChangeText={handleSearch}
value={searchTerm}
containerStyle={styles.searchBarContainer}
inputContainerStyle={styles.searchBarInputContainer}
/>
);
case 'user':
return (
<View style={styles.item}>
<Text style={styles.name}>{item.user.name}</Text>
<Text style={styles.details}>username: {item.user.username}</Text>
<Text style={styles.details}>email: {item.user.email}</Text>
<Text style={styles.details}>phone: {item.user.phone}</Text>
<Text style={styles.details}>website: {item.user.website}</Text>
<Text style={styles.details}>company: {item.user.company.name}</Text>
</View>
);
}
};
return (
// Use SafeAreaView to handle safe area insets
<SafeAreaView style={styles.container}>
<View style={{ flex: 1 }}>
{/* Custom toolbar */}
<Text style={[styles.toolbar, { paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0 }]}>TheDevDigest: Stay Ahead of the Code Curve
</Text>
<FlatList
data={listData} // Data source for FlatList
renderItem={renderItem} // Function to render each item
keyExtractor={(item) => (item.id || item.type).toString()} // Unique key for each item
stickyHeaderIndices={[1]} // Make the second item (search bar) sticky
/>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#151515',
},
toolbar: {
fontSize: 20,
fontWeight: 'bold',
backgroundColor: '#000',
color: '#ffff18',
paddingHorizontal: 10,
paddingVertical: 15,
},
title: {
fontSize: 20,
fontWeight: 'bold',
color: 'white',
paddingHorizontal: 15,
paddingVertical: 15,
},
searchBarContainer: {
borderWidth: 0,
padding: 10,
},
searchBarInputContainer: {
borderRadius: 8,
},
item: {
padding: 16,
backgroundColor: '#1f1f1f',
marginVertical: 4,
},
name: {
fontSize: 20,
fontWeight: 'bold',
color: '#c9c9c9',
},
details: {
color: '#c9c9c9',
}
});
export default App;
Explanation:
-
Installation: We install
react-native-elements
for its pre-builtSearchBar
component. -
Data Structure (
generateListData
): This function structures our data to include the title and search bar at the top of the list. -
State Management: We use
useState
to manage theusers
data, thelistData
for theFlatList
, and thesearchTerm
. -
Data Fetching (
useEffect
): TheuseEffect
hook fetches user data when the component mounts. -
Search Logic (
handleSearch
): This function filters the user data based on the search term. -
Dynamic Rendering (
renderItem
): This function renders different elements based on thetype
of each item in the list. -
Sticky Header (
stickyHeaderIndices
): We use this prop to make the search bar sticky as the user scrolls. -
Styling: (Not shown in code example) You can add custom
styling using
StyleSheet.create
to match your app's design.
This setup creates a user-friendly list with a sticky header and live search, improving the navigation and search experience in your React Native application. Feel free to adapt and customize this code to fit the specific design and functionality of your app.
Comments
Post a Comment