Build a Dynamic Searchable Blog with React Native

Aneeqa Khan - Jul 7 - - Dev Community

In this article, we will explore how to build a React Native app that fetches data from an API, displays it, and includes a search functionality to filter through posts effortlessly.

Let’s dive into the code and uncover the magic behind creating a searchable blog using React Native.


Setting Up the Project

Before we begin, make sure you have a React Native environment set up. You can follow the official React Native documentation to get started.

npx @react-native-community/cli@latest init MyBlogApp
cd MyBlogApp
Enter fullscreen mode Exit fullscreen mode

Install necessary dependencies

npm install
Enter fullscreen mode Exit fullscreen mode

Building the Posts Component

The core of our application is the Posts component. This component will handle fetching posts, displaying them, and providing a search functionality to filter through the posts.

First, I’ll create the UI components: a “Load Posts” button, a text input for filtering posts, and a FlatList for displaying the list of posts.

import React, { useState } from "react";
import {
  Text,
  View,
  Pressable,
  FlatList,
  TextInput,
  StyleSheet,
} from "react-native";
import Post from "./Post";

const Posts = () => {
  const [posts, setPosts] = useState([]);
  const [filteredPosts, setFilteredPosts] = useState([]);
  const [loaded, setLoaded] = useState(false);
  const [searchText, setSearchText] = useState("");
  const url = "https://jsonplaceholder.typicode.com/posts";

  return (
    <View style={styles.mainContainer}>
      {!loaded ? (
        <Pressable
          style={styles.loadBtn}
          onPress={() => {}}
        >
          <Text>Load Posts</Text>
        </Pressable>
      ) : (
        <View>
          <View style={styles.searchContainer}>
            <Text>Search: </Text>
            <TextInput
              style={styles.searchField}
              value={searchText}
              onChangeText={() => {}}
            />
          </View>
          <FlatList
            data={filteredPosts}
            keyExtractor={(item) => item.id.toString()}
            renderItem={({ item }) => <Post post={item} />}
            ListEmptyComponent={<Text>No posts found.</Text>}
            contentContainerStyle={styles.postsContainer}
          />
        </View>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  mainContainer: { flex: 1, padding: 30 },
  loadBtn: {
    borderWidth: 1,
    padding: 10,
    alignItems: "center",
    borderRadius: 5,
    backgroundColor: "#f0f0f0",
  },
  searchContainer: {
    flexDirection: "row",
    alignItems: "center",
    alignSelf: "center",
    marginBottom: 20,
  },
  searchField: {
    borderWidth: 1,
    height: 40,
    width: 200,
    borderRadius: 5,
    paddingHorizontal: 10,
  },
  postsContainer: { paddingHorizontal: 20, paddingVertical: 10 },
});

export default Posts;
Enter fullscreen mode Exit fullscreen mode

Get Posts from API

Now, let's write a function to get posts from the external API.

  const getPosts = async () => {
    try {
      const response = await fetch(url);
      const result = await response.json();
      setPosts(result);
      setFilteredPosts(result);
      setLoaded(true);
    } catch (error) {
      console.error("Failed to fetch posts:", error);
    }
  };

...
  <Pressable
    style={styles.loadBtn}
    testID="load-posts"
    onPress={getPosts}
  >
    <Text>Load Posts</Text>
  </Pressable>
...
Enter fullscreen mode Exit fullscreen mode

Write Logic for Filtration

Here, I am checking the post title and body for the searched text and updating the displayed posts accordingly.

  const filterPosts = (text) => {
    setSearchText(text);
    if (text) {
      const lowercasedText = text.toLowerCase();
      const updatedPosts = posts.filter(
        (post) =>
          post.title.toLowerCase().includes(lowercasedText) ||
          post.body.toLowerCase().includes(lowercasedText)
      );
      setFilteredPosts(updatedPosts);
    } else {
      setFilteredPosts(posts);
    }
  };

...
<TextInput 
  ...
  onChangeText={filterPosts}
/>
...
Enter fullscreen mode Exit fullscreen mode

Understanding the Code

  • State Management: We use React’s useState to manage the state for posts, filtered posts, loading status, and search text.
  • Fetching Data: The getPosts function fetches data from the JSONPlaceholder API and updates the posts state.
  • Filtering Posts: The filterPosts function filters posts based on the search text. If the search text matches any part of the post title or body, it includes that post in the filtered list.
  • Rendering Posts: Depending on whether there is search text, we display either the complete list of posts or the filtered list.

Creating the Post Component

Create a Post component to display individual posts

import React from "react";
import { View, Text, StyleSheet } from "react-native";

const Post = ({ post }) => {
  return (
    <View style={styles.postContainer}>
      <Text style={styles.postTitle}>{post.title}</Text>
      <Text>{post.body}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  postContainer: { padding: 10, borderBottomWidth: 1, borderColor: "#ddd" },
  postTitle: { fontSize: 18, fontWeight: "bold" }
});

export default Post;
Enter fullscreen mode Exit fullscreen mode

Running the Application

To run your React Native app, use the following command

npx react-native run-android
# or
npx react-native run-ios
Enter fullscreen mode Exit fullscreen mode

Demo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .