React Native (RN): Creating a Sticky Header with FlatList and Search Functionality

React Native (RN): Creating a Sticky Header with FlatList and Search Functionality | TheDevDigest

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.

React Native (RN): Creating a Sticky Header with FlatList and Search
  Functionality | TheDevDigest

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:

  1. Installation: We install react-native-elements for its pre-built SearchBar component.
  2. Data Structure (generateListData): This function structures our data to include the title and search bar at the top of the list.
  3. State Management: We use useState to manage the users data, the listData for the FlatList, and the searchTerm.
  4. Data Fetching (useEffect): The useEffect hook fetches user data when the component mounts.
  5. Search Logic (handleSearch): This function filters the user data based on the search term.
  6. Dynamic Rendering (renderItem): This function renders different elements based on the type of each item in the list.
  7. Sticky Header (stickyHeaderIndices): We use this prop to make the search bar sticky as the user scrolls.
  8. 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