Migrating from SearchKit to ReactiveSearch

Yash Joshi
All things #search
Published in
8 min readAug 29, 2019

--

Image: ReactiveSearch — An open-source UI components library for building search UIs

One of the most frequent questions we see from potential ReactiveSearch users is “How to Migrate my existing Search App to use ReactiveSearch”? “Do you support <X>”? In this post, we will cover this question using one of the early and still popular alternative for building Search UIs with ElasticSearch — SearchKit as a reference.

We’ve also written a migration guide from Algolia’s InstantSearch UI to ReactiveSearch. You can read it here.

ReactiveSearch 3.0 is out now. Read all about it over here.

ReactiveSearch is one of the most actively maintained UI libraries out there (we try!), you can see our activity pulse over here. Since our original library for React was released in 2017, we have addressed over 1,000 issues and PRs, seen our users use it in a variety of contexts and released equivalent React Native and Vue.JS versions. We are actively working on bringing variants of ReactiveSearch to all JS frameworks, as well as porting it to Android currently.

🚀 We now also offer a marketplace of boilerplate ReactiveSearch apps — with use-cases varying from building datagrid layouts zto a full-stack e-commerce app to using different design kits with ReactiveSearch.

Follow Along

To make this easy to follow, I will be migrating a BookSearch app from SearchKit to ReactiveSearch.

Live demo of both the versions that can be browsed at the below links:

SearchKit App Link: https://tender-brown-c5d69b.netlify.com/
ReactiveSearch App Link: https://hungry-ramanujan-ac1399.netlify.com/

Setting Up ElasticSearch

Setting up and maintaining our own search engine cluster can be time-consuming and costly. So we will be using Appbase.io for this. At appbase.io, we have also built some dev tools to help you do all these things within a matter of clicks.

  • A tool to add data into ElasticSearch — Importer
  • A tool to view ElasticSearch data like an excel sheet — Data Browser
  • A tool to generate relevant ElasticSearch queries easily — Query Builder

Setting up the backend ⚒

As mentioned above, we will be using an appbase.io hosted ElasticSearch index. In order to make the BookSearch application, we will need a dataset of some really good books. I have already created an appbase.io app with the books dataset indexed over here. You can either clone this dataset to use your own credentials or copy the below credentials to follow along:

url="https://scalr.api.appbase.io/new-book-search"
credentials="vrTi58e8o:04540063-5d81-4fb1-9969-a52d29892995"

I have used these credentials to create a SearchKit application. You can check the codebase for the app here.

Migrating from SearchKit 🚀

I will be going through the migration of this app in an easy to follow along with style and will use CodeSandbox to track each step. I have already set up the initial codesandbox for you in order to make the migration easy. You can check it here.

Structure of the app:

.
├── src
│ ├── index.js Entry Point
│ ├── App.js Renders all the component
│ ├── constant.js Contains Credentials & name
│ └── components
│ ├── Filters.js Render all Filters
│ ├── Results.js Render Result List
│ └── Navbar.js Render Navbar with SearchBar
└── ..

Adding Base Component

SearchKit:
All the SearchKit components are wrapped inside a container called SearchkitProvider which connects the component with elasticsearch index.

We need to create an instance of SearchkitManager and pass it as a prop in SearchkitProvider. Note We can only have one child in SearchkitProvider so to accommodate multiple children we need to wrap it with another element.

ReactiveSearch:
All the ReactiveSearch components are wrapped inside a container component — ReactiveBase which connects the components to an Elasticsearch index. We’ll apply this in the /src/App.js file. You can read more about Reactivebase here.

Since we are using the appbase.io app, we just need to pass app name and credentials. We are also using the theme prop to match the default theme of Searchkit. You can read more about ReactiveBase here.

We have connected our ElasticSearch index with the UI using the base component. We can now proceed to add other components.

ElasticSearch Index connected with UI ✨

Integrating Search in Navbar 🔍

We need a search box UI in Navbar to search across various authors & books. We need to add this component in /src/components/Navbar.js.

SearchKit:
SearchBox is the component which allows users to type their search queries. You can read more about the component here.

ReactiveSearch:
DataSearch is the component which allows users to type their search queries. You can read more about the component here.

  • componentId String
    unique identifier of the component.
  • dataField String or Array
    database field(s) to be connected to the component’s UI view. DataSearch accepts an Array in addition to String, useful for applying search across multiple fields.
  • fieldWeights Array
    set the search weight for the database fields, useful when dataField is an Array of more than one field. This prop accepts an array of numbers. A higher number implies a higher relevance weight for the corresponding field in the search results.
  • placeholder String
    set the placeholder text to be shown in the search box input field. Defaults to Search.
  • autosuggest Boolean
    set whether the autosuggest functionality should be enabled or disabled. Defaults to true.

When we add this component in Navbar.js, we will see a Search box appearing on the right side of the navigation bar.

DataSearch added in Navbar 🔎

ReactiveSearch also provides a component called CategorySearch which can be used to search across various categories. You can read more here.

Displaying books in the Results section 📚

As we now have the search bar in place, we need to now display the books that the user has searched in DataSearch . We will display books in Result Section that is we need to make changes in src/components/Results.js .

In SearchKit:
Hits component displays result from ElasticSearch. To customise each result, you need to implement a React component and pass into the itemComponent prop. The component will receive a single hit object from the search results, which will include result._source which contains the untouched stored fields which were indexed.

Pagination component provides the ability to traverse through pages.

NoHits component comes handy when there are no results present and can be used to display a message accordingly.

InitialLoader component is used to show loading status while the data is being fetched from the index.

In the below snippet notice that on Line 3we are passing another component called ResultCard . This component just renders the data from ElasticSearch in the card format.

In ReactiveSearch:

ReactiveList creates a data-driven result UI component. This list can reactively update itself based on changes in other components or changes in the database itself.

We have two other result components along with ReactiveListResultList & ResultCard. In our case, we can make use of the ResultCard component and render the data from ElasticSearch in card format. You can read more about Results component here.

Props Used:

  • componentId String
    unique identifier of the component, can be referenced in other components’ react prop.
  • dataField String
    data field to be connected to the component’s UI view. It is useful for providing a sorting context.
  • pagination Boolean
    Defaults to false. When set to true, a pagination based list view with page numbers will appear.
  • react
    allows components to watch each other components and update their data reactively. For example, a Result component can update its data based on the selected fields DataSearch component. We define dependency using componentId. You can read more about the react prop over here.

Note: You can also use renderItem & render prop here to render the UI. Learn more about this props here.

Displaying books in Results Section 📚

Integrating different facets in the filters section 📙

We now have all the books listed in the Result section, now we can add different facets to filter out the books. Both SearchKit & ReactiveSearch provides a number of facets to be used, here we will be taking a look at few of them.

Multiple selection based list Filter:

In SearchKit:
RefinementList lets the user refines the search results. You can specify if you want filters to be OR’ed or AND’ed. For example, if you filter on a and b with OR, results with either the value a or b will match.

In ReactiveSearch:
MultiList creates multiple selections based list UI component that is connected to a database field. MultiList component is similar to RefinementListFilter as you can see in the below snippet.

Props used:

  • componentId String
    unique identifier of the component can be referenced in other components’ react prop.
  • dataField String
    data field to be connected to the component’s UI view. This field is used for doing aggregation and returns the result.
  • title String or JSX
    title of the component to be shown in the UI. Defaults to no title being shown.
  • queryFormat String
    queries the selected items from the list in one of two modes: or, and.
  • showSearch Boolean
    whether to show a search box to filter the list items locally. Defaults to true.

You can learn about more props here.

Range slider based Filter:

In SearchKit:
RangeFilter lets users filter results within a numerical range. Provides a histogram to show the user where results are found on the range. Read more here.

In ReactiveSearch:
RangeSlider creates a numeric range slider UI component. It is used for granular filtering of numeric data. There is not much code difference except in ReactiveSearch min & max are defined in the range prop.

Props Used:

  • componentId String
    unique identifier of the component can be referenced in other components’ react prop.
  • dataField String
    DB data field to be mapped with the component’s UI view. The selected range creates a database query on this field.
  • range Object
    an object with start and end keys and corresponding numeric values denoting the minimum and maximum possible slider values.
  • rangeLabels Object
    an object with start and end keys and corresponding String labels to show labels near the ends of the RangeSlider component.
  • title String or JSX
    title of the component to be shown in the UI.

Numeric range selection Filter:

In SearchKit:
NumericRefinementList allows the user to refine results based on a numerical ElasticSearch field. You can specify an array of options for the user to select from. Will only allow the user to select one.

In ReactiveSearch:
SingleRange creates a numeric range selector UI component that is connected to a database field.

  • componentId String
    unique identifier of the component can be referenced in other components’ react prop.
  • dataField String
    data field to be connected to the component’s UI view. The range items are filtered by a database query on this field.
  • data Object Array
    collection of UI labels with associated start and end range values.
  • showRadio Boolean
    show radio button icon for each range item. Defaults to true.
  • showFilter Boolean
    show the selected item as a filter in the selected filters view. Defaults to true.
  • title String or JSX
    title of the component to be shown in the UI.

Note: In order to update Results reactively according to the filter, we will need to add them in the react prop of ReactiveList.

Adding Selected Filter ✅

Now we have the search app ready, but we want our users to know which filters are applied. We will show these filters above result items.

SelectedFilters is the component that is used in both SearchKit and ReactiveSearch to create a selectable filter UI view displaying the currently selected values from other components. This component is useful for improving selection accessibility of other components.

Adding this component in src/components/Results.js :

At Line 2 we have introduced the filters component. You can read more about this component here.

With the addition of SelectedFilters, we have completely migrated the SearchKit app to ReactiveSearch app.

Final App after Migration 💥

Styling 🖌

SearchKit uses BEM concepts to style a component whereas ReactiveSearch provide a prop called innerClass to inject class name to different sub-components. ReactiveSearch also provides theming support via the theme prop.

Porting Custom UI Components 📈

ReactiveSearch is designed to support custom UI components built with an external design kit. ReactiveComponent allows you to use any component and still take advantage of ReactiveSearch’s state management and declarative props.

I hope this post has been helpful to you in understanding how a potential migration from SearchKit to ReactiveSearch can work out.

Cheers! 🥂

--

--