Guides / Building Search UI / Upgrade guides

Upgrading React InstantSearch Hooks

React InstantSearch Hooks and React InstantSearch are separate, incompatible libraries.

React InstantSearch is a standalone library with ready-to-use UI components. React InstantSearch Hooks is based on InstantSearch.js, and lets you fully control the rendering. With React InstantSearch Hooks, you can create your own UI components using React Hooks.

This guide helps you migrate from React InstantSearch v6 to React InstantSearch Hooks v6. If you’re using React InstantSearch < 6, please upgrade to v6 first.

Components

React InstantSearch Hooks provides most of the same UI components as React InstantSearch. When no UI component is available, you can use the matching Hooks to build it yourself.

React InstantSearch React InstantSearch Hooks
<Breadcrumb> <Breadcrumb>
<ClearRefinements> <ClearRefinements>
<Configure> <Configure>
<CurrentRefinements> <CurrentRefinements>
<DynamicWidgets> <DynamicWidgets>
<EXPERIMENTAL_Answers> useConnector(connectAnswers) (no UI component)
EXPERIMENTAL_useAnswers() useConnector(connectAnswers) (no UI component)
<ExperimentalConfigureRelatedItems> useConnector(connectConfigureRelatedItems) (no UI component)
<HierarchicalMenu> <HierarchicalMenu>
<Highlight> <Highlight>
<Hits> <Hits>
<HitsPerPage> <HitsPerPage>
<Index> <Index>
<InfiniteHits> <InfiniteHits>
<InstantSearch> <InstantSearch>
<Menu> <Menu>
<MenuSelect> useMenu() (no UI component)
<NumericMenu> useConnector(connectNumericMenu) (no UI component)
<Pagination> <Pagination>
<Panel> No equivalent available
<PoweredBy> <PoweredBy>
<QueryRuleContext> useQueryRules() (no UI component)
<QueryRuleCustomData> useQueryRules() (no UI component)
<RangeInput> <RangeInput>
<RangeSlider> useRange() (no UI component)
<RatingMenu> useMenu() (no UI component)
<RefinementList> <RefinementList>
<RelevantSort> useConnector(connectRelevantSort) (no UI component)
<ScrollTo> No equivalent available
<SearchBox> <SearchBox>
<Snippet> <Snippet>
<SortBy> <SortBy>
<Stats> No equivalent available
<ToggleRefinement> <ToggleRefinement>
<VoiceSearch> useConnector(connectVoiceSearch) (no UI component)

Component props differ slightly between React InstantSearch and React InstantSearch Hooks. Refer to the API reference of each component for information.

The <Menu> widget in React InstantSearch Hooks isn’t searchable. You can create a searchable version by using a custom widget with the useRefinementList() connector.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import {
  useRefinementList,
  useInstantSearch,
} from 'react-instantsearch-hooks-web';

function Menu({ attribute, ...props }) {
  const { setIndexUiState } = useInstantSearch();
  const { items, searchForItems, isFromSearch } = useRefinementList({
    attribute,
  });
  const [query, setQuery] = React.useState('');

  function refine(value: string) {
    setQuery('');
    setIndexUiState((uiState) => ({
      ...uiState,
      refinementList: {
        ...uiState.refinementList,
        [attribute]: [value],
      },
    }));
  }

  return (
    <div {...props}>
      <input
        type="search"
        value={query}
        onChange={(event) => {
          const nextValue = event.target.value;
          setQuery(nextValue);
          searchForItems(nextValue);
        }}
      />
      <ul>
        {items.map((item) => (
          <li key={item.label}>
            <label>
              <input
                type="radio"
                checked={item.isRefined}
                onChange={() => refine(item.value)}
              />
              {isFromSearch ? (
                <Highlight hit={mapToHit(item)} attribute="highlighted" />
              ) : (
                item.label
              )}
            </label>
          </li>
        ))}
      </ul>
    </div>
  );
}

function mapToHit(item: RefinementListItem): AlgoliaHit<RefinementListItem> {
  return {
    ...item,
    _highlightResult: {
      highlighted: {
        value: item.highlighted,
        matchLevel: 'full',
        matchedWords: [],
      },
    },
    __position: 0,
    objectID: '',
  };
}

Connectors

React InstantSearch Hooks provides the same connectors as React InstantSearch except the connectStateResults connector, which isn’t available in React InstantSearch Hooks.

connectStateResults

React InstantSearch Hooks doesn’t have the connectStateResults connector. You can use the useInstantSearch() hook instead.

Using connectors and Hooks

React InstantSearch Hooks is a bridge between InstantSearch.js connectors and React Hooks. The connectors from React InstantSearch and InstantSearch.js were historically different APIs, meaning there are differences between the props that React InstantSearch connectors accept and the new Hooks.

Refer to the API reference to see the new props.

The React InstantSearch Hooks package uses TypeScript natively. If your editor supports code completion (IntelliSense), you can use it to discover the new props.

Creating connectors

The connector API has changed to use InstantSearch.js connectors. The previous createConnector() function is no longer available.

React InstantSearch Hooks works with all InstantSearch.js connectors—official Algolia connectors, and community ones.

To create your own Hook, you can use an existing connector or create your InstantSearch.js connector.

Routing

Routing now follows the InstantSearch.js routing APIs with the <InstantSearch> routing prop.

Server-side rendering (SSR)

The server APIs have been simplified in React InstantSearch Hooks.

Replace findResultsState() with getServerState(). This new API accepts an element <App />. You can pass props directly to <App />.

In your server code, you don’t need to provide your index name and your search client anymore, because they’re already in your <App>.

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
32
33
34
35
36
37
38
39
40
41
42
 import express from 'express';
 import React from 'react';
 import { renderToString } from 'react-dom/server';
-import { findResultsState } from 'react-instantsearch-dom/server';
+import { getServerState } from 'react-instantsearch-hooks-server';
 import App from './App';

-const indexName = 'instant_search';
-const searchClient = algoliasearch('YourApplicationID', 'YourSearchOnlyAPIKey');

 const app = express();

 app.get('/', async (req, res) => {
-  const searchState = { /* ... */ };
-  const serverState = {
-    resultsState: await findResultsState(App, {
-      searchClient,
-      indexName,
-      searchState,
-    }),
-    searchState,
-  };
+  const serverState = await getServerState(<App />);
   const html = renderToString(<App serverState={serverState} />);

   res.send(
     `
   <!DOCTYPE html>
   <html>
     <head>
       <script>window.__SERVER_STATE__ = ${JSON.stringify(serverState)};</script>
     </head>
     <body>
       <div id="root">${html}</div>
     </body>
     <script src="/assets/bundle.js"></script>
   </html>
     `
   );
 });

 app.listen(8080);

You don’t need to pass any props to <InstantSearch> to support SSR, only wrap the component to render on the server with <InstantSearchSSRProvider>. Then, pass the server state by spreading the getServerState() prop.

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
 import algoliasearch from 'algoliasearch/lite';
 import React from 'react';
-import { InstantSearch } from 'react-instantsearch-dom';
+import {
+  InstantSearch,
+  InstantSearchSSRProvider,
+} from 'react-instantsearch-hooks-web';

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

 function App(props) {
   return (
+    <InstantSearchSSRProvider {...props.serverState}>
       <InstantSearch
         indexName="instant_search"
         searchClient={searchClient}
-        resultsState={props.serverState.resultsState}
-        onSearchParameters={props.onSearchParameters}
-        widgetsCollector={props.widgetsCollector}
       >
         {/* Widgets */}
       </InstantSearch>
+    </InstantSearchSSRProvider>
   );
 }

 export default App;

Types

Types are now available in React InstantSearch Hooks.

You can uninstall all InstantSearch types coming from DefinitelyTyped.

1
2
3
yarn remove @types/react-instantsearch-dom @types/react-instantsearch-core @types/react-instantsearch
# or
npm uninstall @types/react-instantsearch-dom @types/react-instantsearch-core @types/react-instantsearch

Default Refinement

In React InstantSearch, every widget has a defaultRefinement prop. This doesn’t exist in React InstantSearch hooks and is replaced with initialUiState.

Controlled mode

The props searchState and onSearchStateChange are equivalent to the onStateChange prop.

Did you find this page helpful?