Nelson Michael Nelson Michael is a frontend developer from Nigeria. When he's not meddling with CSS, he spends his time writing, sharing what he knows, and playing games.

Best React Native search libraries

9 min read 2753 107

Best React Native Search Libraries

Search functionality is a vital component of many mobile applications, enabling users to quickly find the content they need. When it comes to developing mobile apps using React Native, there are several libraries available that can enhance and make the search experience more efficient.

In this article, we’ll explore two of the best React Native search libraries for integrating powerful search capabilities into applications. Whether you’re building a simple note-taking app or a complex ecommerce platform, these libraries will enable you to create a seamless and intuitive search feature that boosts user satisfaction and engagement.

Let’s dive into the world of React Native search libraries and discover which ones stand out from the rest.

Jump ahead:

React InstantSearch Hooks

React InstantSearch Hooks is an Algolia-powered library specifically designed for building search interfaces. It’s compatible with React Native applications using Hooks and offers a comprehensive set of components and Hooks that allow you to create fast and interactive search experiences. With features like instant search, autocomplete, and faceted filtering, React InstantSearch Hooks provides seamless integration with Algolia’s search platform simplifying the implementation of search functionality in React Native applications.

To begin searching our content, we’ll need to transfer your data to Algolia. Instead of searching within our original data source, Algolia performs searches on the data we provide, which is stored on Algolia’s servers.

Here’s the step-by-step process:

  1. Retrieve data from our various sources, such as a database or static files
  2. Convert the collected data into JSON records
  3. Submit the records to Algolia using one of the available methods: a connector, an API client, the Algolia CLI, or the Algolia dashboard; this step is referred to as indexing, where the data is transferred to Algolia’s servers for search operations

<N.B., we’ll also have to build a search user interface where we can use the Hooks from React InstantSearch Hooks that let us perform operations on our indexed data

Installation

To begin using React Native InstantSearch, start by installing the package using npm or Yarn:

npm install algoliasearch react-instantsearch-hooks

or

yarn add algoliasearch react-instantsearch-hooks

Once the installation is complete, we can import the necessary components from the library in our React Native application.

To enable simple search functionality, we can wrap our application’s root component with the InstantSearch provider component. This component provides the context for all InstantSearch-related components and handles communication with Algolia’s search API:

import React from 'react';
import { SafeAreaView, StatusBar, View } from 'react-native';
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch } from 'react-instantsearch-hooks';

const searchClient = algoliasearch('ApplicationID', 'SearchOnlyAPIKey');

export default function App() {
  return (
    <SafeAreaView>
      <StatusBar style="light" />
      <View>
        <InstantSearch searchClient={searchClient} indexName="instant_search">
          {/* Rest of your application*/}
        </InstantSearch>
      </View>
    </SafeAreaView>
  );
}

The library offers inbuilt UI components that are designed for web-based applications and may not be directly compatible with React Native, but we can still utilize Hooks with the core components of React Native or any third-party React Native component library. This allows us to leverage the functionality and benefits of Hooks while working with React Native in combination with the library.

Let’s see how we can perform some operations on our data in a React Native application using React InstantSearch Hooks.

Searching

The primary element in a search interface is typically a search box. Since we can‘t use the Searchbox component in React Native, React InstantSearch Hooks offers a convenient useSearchBox() Hook that facilitates the creation of a custom search box connected to Algolia.



This Hook can be effectively combined with the <TextInput> component provided by React Native. By using these tools together, we can easily implement a search box integrated with Algolia’s search functionality in your React Native application:

import React, { useRef, useState } from 'react';
import {View, TextInput, StyleSheet } from 'react-native';
import { useSearchBox } from 'react-instantsearch-hooks';

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#00000080',
    padding: 14,
  },
  input: {
    height: 48,
    padding: 16,
    fontSize: 16,
    backgroundColor: '#ffffff',
    borderRadius: 8,
    borderWidth: 1,
    borderColor: '#D9D9D9',
  },
});

export const SearchBox = (props) => {
  const { query, refine } = useSearchBox(props);
  const [searchValue, setSearchValue] = useState(query);
  const inputRef = useRef(null);

 const updateQuery = (newQuery) => {
    setSearchValue(newQuery);
    refine(newQuery);
  }

  if (query !== searchValue && !inputRef.current?.isFocused()) {
    setSearchValue(query);
  }

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        ref={inputRef}
        value={searchValue}
        onChangeText={updateQuery}
        clearButtonMode="while-editing"
        placeholder='Search'
      />
    </View>
  );
}

React InstantSearch Hook Search Component

Now we can just add our SearchBox component inside of our application by calling it here in the app component:

<InstantSearch searchClient={searchClient} indexName="instant_search">
    {/* Rest of your application*/}
  <SearchBox />
</InstantSearch>

This search input works fine, but now we need to display the search query results (i.e., “hits”). A popular approach for displaying lists on mobile devices is to implement an infinite list that dynamically loads additional results as the user scrolls to the bottom of the screen.

To accomplish this, we can use the useInfiniteHits() Hook along with the <FlatList> component from React Native. This combination allows us to show Algolia hits and automatically load more results when the end of the list is reached:

import React from 'react';
import { View, FlatList } from 'react-native';
import { useInfiniteHits } from 'react-instantsearch-hooks';

export const SearchResults = (props) => {
  const { hits, isLastPage, showMore } = useInfiniteHits(props);

  return (
    <FlatList
      data={hits}
      keyExtractor={(item) => item.objectID}
      onEndReached={() => {
        if (!isLastPage) {
          showMore();
        }
      }}
      renderItem={({ item }) => (
        <View>
          <Hit hit={item} />
        </View>
      )}
    />
  );
};

const Hit = ({ hit }) => {
  return (
    <Text>{hit.name}</Text>
  );
}

We can add our SearchResults component to our application by calling it in the app component, like so:

<InstantSearch searchClient={searchClient} indexName="instant_search">
    {/* Rest of your application*/}
  <SearchBox />
  <SearchResults />
</InstantSearch>

As the user inputs a query, the list will dynamically update, displaying the search results obtained from Algolia. By scrolling down, the user can trigger the loading of additional hits for continuous browsing.

Filtering

Given the limited screen space on mobile devices, it is common practice to place filters inside a modal instead of displaying them alongside the list of hits as we would on a desktop website. In React Native, we can achieve this by utilizing the <Modal> component provided by the framework:

import React from 'react';
import {
  Button,
  SafeAreaView,
  Modal,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';
import {
  useClearRefinements,
  useCurrentRefinements,
  useRefinementList,
} from 'react-instantsearch-hooks';

export const Filters = ({ isModalOpen, onToggleModal }) => {
  const { items, refine } = useRefinementList({ attribute: 'brand' });
  const { canRefine: canClear, refine: clear } = useClearRefinements();
  const { items: currentRefinements } = useCurrentRefinements();
  const totalRefinements = currentRefinements.reduce(
    (acc, { refinements }) => acc + refinements.length,
    0
  );

  return (
    <>
      <TouchableOpacity onPress={onToggleModal}>
        <Text>Filters</Text>
        {totalRefinements > 0 && (
          <View>
            <Text>{totalRefinements}</Text>
          </View>
        )}
      </TouchableOpacity>

      <Modal animationType="slide" visible={isModalOpen}>
        <SafeAreaView>
          <View>
            <View>
              <Text>Brand</Text>
            </View>
            <View>
              {items.map((item) => {
                return (
                  <TouchableOpacity
                    key={item.value}
                    onPress={() => {
                      refine(item.value);
                      onChange();
                    }}
                  >
                    <Text>
                      {item.label}
                    </Text>
                    <View>
                      <Text>{item.count}</Text>
                    </View>
                  </TouchableOpacity>
                );
              })}
            </View>
          </View>
          <View>
            <View>
              <Button
                title="Clear all"
                disabled={!canClear}
                onPress={() => {
                  clear();
                  onToggleModal();
                }}
              />
            </View>
            <View style={styles.filterListButton}>
              <Button
                onPress={onToggleModal}
                title="Results"
              />
            </View>
          </View>
        </SafeAreaView>
      </Modal>
    </>
  );
}

Within the component, several Hooks and variables are used to handle filtering functionality:

  1. useRefinementList Hook: initializes a refine function and an items array for the attribute “brand”; allows the user to select specific brands for filtering
  2. useClearRefinements Hook: provides a canClear Boolean flag and a clear function; indicates whether any refinements are available and allows the user to clear the applied filters
  3. useCurrentRefinements Hook: retrieves the current refinements made by the user and assigns them to the currentRefinements variable
  4. totalRefinements variable: calculates the total number of refinements by iterating through the currentRefinements array and summing up the lengths of each refinement

We can also add our Filters component to our application by calling it in the app component. We’ll also add a state to toggle the modal open and close:

const [isModalOpen, setModalOpen] = useState(false);

<InstantSearch searchClient={searchClient} indexName="instant_search">
  <SearchBox />
  <Filters
    isModalOpen={isModalOpen}
    onToggleModal={() => setModalOpen((isOpen) => !isOpen)
  />
  <SearchResults />
</InstantSearch>

Sorting

React InstantSearch Hooks lets us create our own UI for the <SortBy> widget with useSortBy(). Here’s an example from React InstantSearch Hooks on how to do that:

import React from 'react';
import { useSortBy } from "react-instantsearch-hooks";
import Box from '@mui/material/Box';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select from '@mui/material/Select';

export function CustomSortBy(props) {
  const { currentRefinement, options, refine } = useSortBy(props);

  return (
    <Box>
      <FormControl>
        <InputLabel>Sort by</InputLabel>
        <Select
          value={currentRefinement}
          onChange={(event) => refine(event.target.value)}
        >
          {options.map((item) => (
            <MenuItem key={item.value} value={item.value}>
              {item.label}
            </MenuItem>
          ))}
        </Select>
      </FormControl>
    </Box>
  );
}

We can add our CustomSortBy component to our application by calling it in the app component:

const [isModalOpen, setModalOpen] = useState(false);

<InstantSearch searchClient={searchClient} indexName="instant_search">
  <SearchBox />
  <CustomSortBy
    items={[
      { label: 'Featured', value: 'instant_search' },
      { label: 'Price (asc)', value: 'instant_search_price_asc' },
      { label: 'Price (desc)', value: 'instant_search_price_desc' },
    ]}
  />
  <Filters
    isModalOpen={isModalOpen}
    onToggleModal={() => setModalOpen((isOpen) => !isOpen)
  />
  <SearchResults />
</InstantSearch>

With the useSortBy Hook, we can implement a feature that presents a list of indices for users to choose from, enabling them to modify the sorting of hits using replica indices. This functionality allows us to create sorted replica datasets on our dashboard. When users select any of the provided sorting options, the corresponding replica data is displayed.

In the previous example, we offered users the ability to sort data in ascending or descending order. When a user clicks on any of these options, the replica data associated with that specific sorting option is shown.

N.B., feel free to explore the< API reference to discover additional Hooks that can further enhance your implementation

ReactiveSearch

ReactiveSearch is a powerful React Native library that simplifies the implementation of advanced search functionality in mobile. It offers a range of powerful search components, including the React Native SearchBox. This library simplifies the process of building search functionality by providing inbuilt UI components and a robust set of Hooks.

Installation

To begin using Reactive search with React Native, start by installing the package using npm or Yarn:

npm install @appbaseio/reactivesearch-native

or

yarn add @appbaseio/reactivesearch-native

Once the installation is complete, we can import the necessary components from the library in our React Native application.

To use ReactiveSearch, we’ll need to add our dataset to Elasticsearch, which ReactiveSearch uses as its underlying database system. An app within ReactiveSearch’s context refers to an index in Elasticsearch. Here’s a guide on how you can import your data.

To begin integrating ReactiveSearch into our project, we will use the ReactiveBase component. This component acts as a backend connector, allowing us to configure the Elasticsearch index and handle authorization setup:

import React from 'react';
import { Text, View } from 'react-native';
import { ReactiveBase } from '@appbaseio/reactivesearch-native';

export const App = () => {
      return (
        <ReactiveBase
            app="YOUR_APP_NAME"
            credentials="YOUR_CREDENTIALS"
        >
          {/* Rest of your application*/}
      </ReactiveBase>
  );
}

Unlike React InstantSearch Hooks, ReactiveSearch provides a slew of components that we can use to handle various operations on our dataset. Let’s take a closer look to see some of them in action.

Searching

We can set up a basic search functionality using the DataSearch component:

import React from 'react';
import {StyleSheet} from 'react-native'
import { ReactiveBase, DataSearch, ReactiveList } from '@appbaseio/reactivesearch-react-native';

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#00000080',
    padding: 14,
  },
  searchInput: {
    fontSize: 16,
    backgroundColor: '#ffffff',
    borderWidth: 1,
    borderColor: '#D9D9D9',
  },
});

const searchUI = () => {
 return (
    <ReactiveBase
  app="YOUR_APP_NAME"
  credentials="YOUR_CREDENTIALS" >
    <SafeAreaView>
      <View style={styles.container}>
          <DataSearch
            componentId="searchComponent"
            dataField="title"
            placeholder="Search..."
            style={styles.searchInput}
          />
          <ReactiveList
            componentId="resultList"
            dataField="title"
            size={10}
            renderItem={({ item }) => <Text>{item.title}</Text>}
          />
      </View>
    </SafeAreaView>
  </ReactiveBase>
  )
}

ReactiveSearch Searching

Here, we wrap our search components with the ReactiveBase component, providing the application name and credentials for our Elasticsearch index. The DataSearch component handles the search input, while the ReactiveList component displays the search results.

Filtering

The MultiDropdownList component creates a dropdown list with multiple-select options for filtering. We can add this component allow users to enable filtering functionality based on movie genre:

    <ReactiveBase
      app="YOUR_APP_NAME"
      credentials="YOUR_CREDENTIALS"
    >
      <DataSearch
        componentId="searchComponent"
        dataField="title"
        placeholder="Search..."
      />
      <MultiDropdownList
        componentId="filterComponent"
        dataField="genre"
        title="Filter By Genre"
      />
      <ReactiveList
        componentId="resultList"
        dataField="title"
        size={10}
        renderItem={({ item }) => <Text>{item.title}</Text>}
      />
    </ReactiveBase>

In the above code, we assign the MultiDropdownList component a componentId filter component and a dataField prop that specifies the Elasticsearch field to be used for filtering. The "title" prop sets the title of the dropdown list.

With this setup, users can enter search queries in the search input field, DataSearch, and the search results, ReactiveList, will be updated accordingly. Additionally, users can select multiple genre options from the dropdown list (MultiDropdownList), and the search results will be filtered based on the selected genres.

Sorting

To enhance our search functionality, ReactiveSearch provides options for sorting the search results. We can accomplish this by adding additional components and configuring their properties:

<ReactiveBase
  app="YOUR_APP_NAME"
  credentials="YOUR_CREDENTIALS"
>
  <DataSearch
    componentId="searchComponent"
    dataField="title"
    placeholder="Search..."
  />
  <SingleDropdownList
    componentId="sortComponent"
    dataField="sortField"
    title="Sort By"
    sortBy="title"
    data={[
      { label: 'Relevance', value: 'relevance' },
      { label: 'Date', value: 'date' },
      { label: 'Popularity', value: 'popularity' },
    ]}
    defaultValue="relevance"
  />
  <ReactiveList
    componentId="resultList"
    dataField="title"
    size={10}
    renderItem={({ item }) => <Text>{item.title}</Text>}
  />
</ReactiveBase>

In the above code, the SingleDropdownList component displays a dropdown list for sorting options. It is assigned a componentId sort component and a dataField prop that specifies the Elasticsearch field to be used for sorting. The data prop is an array of objects representing the available sorting options, with each object containing a label and corresponding value. The defaultValue prop sets the initial sorting option.

React InstantSearch Hooks vs. ReactiveSearch: Comparing features

Case React InstantSearch Hooks ReactiveSearch
Backend Specifically tailored for Algolia, a proprietary search engine; built to seamlessly integrate and leverage Algolia’s powerful search capabilities Designed to work seamlessly with Elasticsearch indexes hosted on any Elasticsearch cluster; provides flexibility and compatibility across different environments
Deprecated Actively maintained Actively maintained
Platform Support React, Vue, Angular, vanilla JS for web; React Native for mobile but latter has no UI components React and Vue for web; React Native for mobile
Styling Utilizes CSS-based styles, requiring an external style import for seamless integration. Also supports theming by allowing the manipulation of CSS, providing flexibility in customizing the visual appearance and styling of the components Components are styled and scoped, eliminating the need for external CSS imports. Components offer inbuilt styling options that can be customized using React props, allowing for rich theming capabilities and seamless integration with the overall design of the application
Components Lists, Range, Search, Result; devs can also use their own UI components. Lists, Ranges, Search, Dates, Maps, Result Displays; devs can also use their own UI components.

Conclusion

Incorporating a robust search functionality can significantly enhance the user experience of your React Native application. In this article, we demonstrated how to use the React InstantSearch Hooks and ReactiveSearch libraries with React Native to create a dynamic and interactive search experience.

Both React InstantSearch Hooks and ReactiveSearch offer a range of features and capabilities that can help you achieve efficient and effective search implementation. Whether you prioritize speed, customization, or advanced filtering options, there is a search library out there to meet your specific requirements.

LogRocket: Instantly recreate issues in your React Native apps.

LogRocket is a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.

LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.

Start proactively monitoring your React Native apps — try LogRocket for free.

Nelson Michael Nelson Michael is a frontend developer from Nigeria. When he's not meddling with CSS, he spends his time writing, sharing what he knows, and playing games.

Leave a Reply