Concepts / Building Search UI / Conditional Requests
Jun. 24, 2019

Conditional Requests

Overview

InstantSearch sends a request to Algolia’s servers on every keystroke, which means end users see updated results in real time. Additionally, InstantSearch makes another first request to show the initial results on an empty query. This is the default behavior, which also warms up the network connection and makes subsequent requests faster.

However, there are times when you don’t want to perform more network calls than strictly necessary. For example, when you don’t want to display initial results. This guide helps you build a UI that prevents the initial request on an empty query. You can find the complete example on GitHub.

How it works

InstantSearch is the UI part that sits on top of a search client, with a state managed by the Helper. These three layers are composable, and can be interchanged to leverage the InstantSearch widgets system with a different search client.

The Algolia search client queries Algolia’s servers whenever the end user refines the search. It is possible to build your own search client to implement custom behaviors. This is the approach we take to do back-end search with InstantSearch.

To create your own client, you need to implement a given interface that receives and returns formatted data that InstantSearch can understand.

Implementing a proxy

To prevent searches from happening in certain use cases, we need to wrap a proxy around the Algolia search client. We then pass our custom client to InstantSearch:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch, SearchBox, Hits } from 'react-instantsearch-dom';

const algoliaClient = algoliasearch(
  'YourApplicationID',
  'YourSearchOnlyAPIKey'
);

const searchClient = {
  search(requests) {
    return algoliaClient.search(requests);
  },
};

const App = () => (
  <InstantSearch searchClient={searchClient} indexName="instant_search">
    <SearchBox />
    <Hits />
  </InstantSearch>
);

Functionally speaking, this is no different from directly passing the original client. However, this proxy allows us to perform logic before calling the search method. In our case, we’ll be able to call it conditionally, thus not performing the query when not necessary.

Mocking a search request

We don’t want to perform a search request when the query is empty (""), so we first need to detect it:

1
2
3
4
5
6
7
8
9
const searchClient = {
  search(requests) {
    if (requests.every(({ params }) => !params.query)) {
      // Here we have to do something else
    }

    return algoliaClient.search(requests);
  },
};

In some cases, such as when the end user clicks on a RefinementList, this can trigger multiple requests. We therefore need to make sure that every query is empty before we intercept the function call.

Then, we have to return a formatted response. This is an array of objects of the same length as the requests array. At the bare minimum, each object needs to contain: hits, nbHits, nbPages and processingTimeMS.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const searchClient = {
  search(requests) {
    if (requests.every(({ params }) => !params.query)) {
      return Promise.resolve({
        results: requests.map(() => ({
          hits: [],
          nbHits: 0,
          nbPages: 0,
          processingTimeMS: 0,
        })),
      });
    }

    return algoliaClient.search(requests);
  },
};

Finally, we can use the proxy with the InstantSarch widget, like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch, SearchBox, Hits } from 'react-instantsearch-dom';

const algoliaClient = algoliasearch(
  'YourApplicationID',
  'YourSearchOnlyAPIKey'
);

const searchClient = {
  search(requests) {
    if (requests.every(({ params }) => !params.query)) {
      return Promise.resolve({
        results: requests.map(() => ({
          hits: [],
          nbHits: 0,
          nbPages: 0,
          processingTimeMS: 0,
        })),
      });
    }

    return algoliaClient.search(requests);
  },
};

const App = () => (
  <InstantSearch searchClient={searchClient} indexName="instant_search">
    <SearchBox />
    <Hits />
  </InstantSearch>
);

You can find the complete source code of the example on GitHub.

Prevent Search on Empty Query

In most use-cases, the search-as-you-type behavior of InstantSearch is desirable. This is normally done on every keystroke. However, in order to show your users results from the moment they land on your page, an empty search is performed on page load. If you want to prevent showing results on page load, it makes sense to wait until a user actually starts typing before performing a search.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch, SearchBox, Hits } from 'react-instantsearch-dom';

const algoliaClient = algoliasearch(
  'YourApplicationID',
  'YourSearchOnlyAPIKey'
);

const searchClient = {
  search(requests) {
    const newRequests = requests.map((request)=>{

      // test for empty string and do not trigger search if true
      if(!request.params.query || request.params.query.length===0) {
        return
      }
      return request
    });
    return algoliaClient.search(newRequests);
  },
};

const App = () => (
  <InstantSearch searchClient={searchClient} indexName="instant_search">
    <SearchBox />
    <Hits />
  </InstantSearch>
);

Did you find this page helpful?