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 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:
<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
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.
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> ); }
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.
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:
useRefinementList
Hook: initializes a refine
function and an items
array for the attribute “brand”; allows the user to select specific brands for filteringuseClearRefinements
Hook: provides a canClear
Boolean flag and a clear
function; indicates whether any refinements are available and allows the user to clear the applied filtersuseCurrentRefinements
Hook: retrieves the current refinements made by the user and assigns them to the currentRefinements
variabletotalRefinements
variable: calculates the total number of refinements by iterating through the currentRefinements
array and summing up the lengths of each refinementWe 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>
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 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.
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.
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> ) }
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.
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.
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.
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. |
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 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.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]