DEV Community

Cover image for Full text search with Firestore & Meili search - Implementing Full text search function in React Native app
Gautham Vijayan
Gautham Vijayan

Posted on

Full text search with Firestore & Meili search - Implementing Full text search function in React Native app

In this post, we will be looking into how you can create a search bar interface in your React Native application. We will be creating a React Native project and will be connecting our melli search instance with our frontend app and create a nice search interface.

Lets create a react native app with the following command.


npx react-native init yourappname
cd yourappname

Enter fullscreen mode Exit fullscreen mode

After this lets install libraries called axios to call our APIs. We will also be installing a library called 'react-native-fast-image' which is a brilliant library to cache remote images in react native. We will also be installing lodash to use a function called debounce in Javascript.


npm i react-native-fast-image lodash

Enter fullscreen mode Exit fullscreen mode

After we have installed the packages, we need to run pod install to install necessary pods so that we can run our app in iOS. There is no additional step required for android.


pod install

Enter fullscreen mode Exit fullscreen mode

For M1 macs, you can use the following command to install pods without any errors.


arch -x86_64 pod install

Enter fullscreen mode Exit fullscreen mode

Now lets get into the coding part. We are going to setup a folder called API and create a folder called Components where we will be creating our Search Interface.

Before that I am initialising axios instance to be used in our app.



import axios from 'axios';

export const BASE_URL = 'yourapi.com';

export const instance = axios.create({
  baseURL: BASE_URL,
  headers: {
    'Content-Type': 'application/json',
    Accept: 'application/json',
  },
});


Enter fullscreen mode Exit fullscreen mode

Lets setup our API functions

Now lets create our search input to get data from our API.
This will look and feel the same as the Next JS search interface we have created before



import {instance} from './Api';

export const addResourceFromMelli = async melliSearchData => {
  const melliData = {
    index: 'movies',
    data: melliSearchData?.movieData,
  };

  try {
    await instance.post(`/mellisearch/add-document`, melliData);
  } catch (error) {
    console.log(error);
  }
};

export const searchResourcesFromMelli = async melliSearchData => {
  try {
    const melliData = {
      index: 'movies',
      search: melliSearchData?.search,
    };

    const res = await instance.post(`/mellisearch/search`, melliData);

    return res.data.hits;
  } catch (error) {
    console.log(error);

    return [];
  }
};

export const deleteResourceFromMelli = async melliSearchData => {
  const melliData = {
    index: 'movies',
    id: melliSearchData?.movieId,
  };

  try {
    await instance.post(`/mellisearch/delete-document`, melliData);
  } catch (error) {}
};



Enter fullscreen mode Exit fullscreen mode

Now let us call the API in our debounced search input with help of lodash and retrieve data points and show case it to the frontend.

Here below is the full code of the search interface.


import React, {useState} from 'react';
import {
  View,
  TextInput,
  Text,
  StyleSheet,
  SafeAreaView,
  ScrollView,
  ActivityIndicator,
  Platform,
  Dimensions
} from 'react-native';

import FastImage from 'react-native-fast-image';
import {useCallback} from 'react';
import {searchResourcesFromMelli} from '../API/MellisearchAPI';
import {debounce} from 'lodash';

const screenWidth = Dimensions.get('screen').width

const SearchInterface = () => {
  const [query, setQuery] = useState('');
  const [moviesData, setMoviesData] = useState([]);

  const [searchLoader, setSearchLoader] = useState(false);
  async function searchMelli(e) {
    const melliSearch = {
      search: e,
    };

    const res = await searchResourcesFromMelli(melliSearch);

    setMoviesData(res);

    setSearchLoader(false);
  }

  const debouncedAPICall = useCallback(debounce(searchMelli, 1200), []);

  async function debouncedFullTextSearch(e) {
    setSearchLoader(true);

    setQuery(e);

    debouncedAPICall(e);
  }

  return (
    <SafeAreaView style={styles.container}>
      <ScrollView showsVerticalScrollIndicator={false}>
        <View style={styles.center}>
          <TextInput
            style={styles.searchInput}
            value={query}
            onChangeText={debouncedFullTextSearch}
            placeholder="Search a movie..."
            placeholderTextColor={'black'}
          />
        </View>

        {searchLoader && (
          <View style={styles.searchLoader}>
            <ActivityIndicator color={'#00A9F1'} size={'large'} />
          </View>
        )}

        {moviesData?.length >= 1 ? (
          moviesData?.map(item => {
            return (
              <View style={styles.movieItem} key={item?.movieId}>
                <FastImage
                  style={styles.poster}
                  source={{
                    uri: item.posterUrl,
                    priority: FastImage.priority.high,
                  }}
                  resizeMode="cover"
                />
                <View style={styles.movieDetails}>
                  <Text style={styles.title}>{item.title}</Text>
                  <Text style={styles.description}>{item.description}</Text>
                </View>
              </View>
            );
          })
        ) : (
          <View style={styles.center}>
            {!searchLoader && (
              <View>
                <FastImage
                  source={require('../Assets/SearchMovies.png')}
                  style={styles.searchMovies}
                  resizeMode="contain"
                />
                <View style={styles.center}>
                  <Text style={styles.searchDescription}>
                    Start typing to search movies!
                  </Text>
                </View>
              </View>
            )}
          </View>
        )}
      </ScrollView>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
    padding: 20,
  },
  center: {
    alignItems: 'center',
    justifyContent: 'center',
  },
  searchInput: {
    borderWidth: 1,
    borderColor: '#00A9F1',
    borderRadius: 5,
    paddingLeft: 10,
    marginVertical: 10,
    width: 300,
    fontFamily: 'Pangram-Regular',
    fontSize: 18,
    padding: 15,
    backgroundColor: '#F9FAFC',
    color: 'black',
  },
  movieItem: {
    marginVertical: 10,
    alignItems: 'center',
    backgroundColor: 'white',
    marginHorizontal: 10,
    padding: 5,
    borderColor: '#00A9F1',
    borderWidth: 1,
  },
  poster: {
    width: Platform.OS === 'ios' ? screenWidth * 0.85 : screenWidth * 0.8,
    height: 220,
    resizeMode: 'cover',
    marginVertical: 10,
  },
  movieDetails: {
    marginLeft: 10,
  },
  title: {
    fontSize: 20,
    marginBottom: 5,
    fontFamily: 'Pangram-Bold',
    lineHeight: 26,
  },
  description: {
    fontSize: 17,
    fontFamily: 'Pangram-Regular',
    lineHeight: 26,
    marginBottom: 10,
  },
  searchDescription: {
    fontSize: 22,
    fontFamily: 'Pangram-Regular',
    marginBottom: 10,
  },
  searchLoader: {
    paddingTop: 30,
    marginTop: 20,
    marginBottom: 30,
  },
  searchMovies: {
    width: screenWidth * 0.8,
    height: 300,
  },
});

export default SearchInterface;

Enter fullscreen mode Exit fullscreen mode

Thats it we have successfully integrated a neat search interface for our React Native app.

You can view the complete code and see how the search interface works in a live demo below.

https://github.com/Gautham495/blog-code-snippets

https://demos.gauthamvijay.com/

This concludes the fulltext search feature with multiple technologies like Firebase, Meilisearch, Express JS, React/Next, React Native to make a end to end full text search solution.

Let me know if I can help you in this integration or you need any help in your projects. This series was made to help out developers to make a full text search functionality from the backend to the frontend in a neat concise way.

Top comments (0)