Guides / Building Search UI / Going further

Server-Side Rendering with React InstantSearch

We released React InstantSearch Hooks, a new InstantSearch library for React. We recommend using React InstantSearch Hooks in new projects or upgrading from React InstantSearch.

Server-side rendering (SSR) typically improves SEO and performance. When using SSR, your initial web content is generated on the server: browsers download pages with HTML content already in place.

React InstantSearch is compatible with server-side rendering. We provide an API that works with any SSR solution.

Native

We split this guide into three parts:

  • App.js: the shared main React component between the server and the browser.
  • server.js: the main server entry to a simple Node HTTP server.
  • browser.js: the main browser entry (ultimately gets compiled to bundle.js).

App.js

App.js is the main entry point to your React application, it exports an App component.

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 React from 'react';
import { InstantSearch, SearchBox, Hits } from 'react-instantsearch-dom';

function App({
  searchClient,
  searchState,
  resultsState,
  onSearchParameters,
  widgetsCollector,
  ...props
}) {
  return (
    <InstantSearch
      {...props}
      indexName="indexName"
      searchClient={searchClient}
      searchState={searchState}
      resultsState={resultsState}
      onSearchParameters={onSearchParameters}
      widgetsCollector={widgetsCollector}
    >
      <SearchBox />
      <Hits />
    </InstantSearch>
  );
}

export { App };

Exporting App makes the component available to both the browser and server code.

If you synchronize a searchState to the URL to create a proper routing, you need to pass the searchState to the InstantSearch component.

server.js

We provide an API called findResultsState, available in react-instantsearch-dom/server.

findResultsState is a function that retrieves a resultsState object that populates results in InstantSearch. The function takes two arguments:

  • The InstantSearch parent component that contains the widgets to mount on the page (App in this example).
  • A “props” object, which accepts:
    • searchClient (required): the same search client that you pass to InstantSearch.
    • indexName (required): the same index name that you pass to InstantSearch.
    • searchState: the object that provides your initial state to resultsState. It’s typically used for URL sync and could be set to { query: 'chair' } for example. Make sure that App passes the initial searchState prop to your InstantSearch component.
    • If you need to pass other props to the component, you can add them to the object.
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 React from 'react';
import { createServer } from 'http';
import { renderToString } from 'react-dom/server';
import algoliasearch from 'algoliasearch/lite';
import { findResultsState } from 'react-instantsearch-dom/server';
import { App } from './App';

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

const server = createServer(async (req, res) => {
  // You can get the full `searchState` in the `req` object
  const searchState = { query: 'chair' };
  // If you use a `SortBy` widget, the active index name is `searchState.sortBy`
  const indexName = 'INDEX_NAME';
  const resultsState = await findResultsState(App, {
    searchClient,
    searchState,
    indexName
  });
  const initialState = { searchState, resultsState };
  const html = renderToString(<App {...initialState} />);

  res.send(
    `
<!doctype html>
<html>
  <body>
    <h1>Awesome server-side rendered search</h1>
    <div id="root">${html}</div>

    <script>
      window.__APP_INITIAL_STATE__ = ${JSON.stringify(initialState)};
    </script>
    <!-- This is the build of `browser.js` -->
    <script src="bundle.js"></script>
  </body>
</html>
`
  );
});

server.listen(8080);

To use JSX and import statements, you must transpile your server-side code (e.g., with Babel). The __APP_INITIAL_STATE__ variable ensures that what was sent by the server matches what the browser expects (through a checksum).

browser.js

This last file creates the link between server-rendered code and the application on the browser.

1
2
3
4
5
6
7
8
9
10
11
import React from 'react';
import { render } from 'react-dom';
import algoliasearch from 'algoliasearch/lite';
import { App } from './App';

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

render(
  <App {...window.__APP_INITIAL_STATE__} searchClient={searchClient} />,
  document.querySelector('#root')
);

Express + ReactDOMServer

Express is a minimal and flexible Node.js web application framework. It’s widely adopted in the Node.js ecosystem. An example of React InstantSearch and Express is available on our GitHub repository.

Next.js

Next.js is a framework that wraps and abstracts the more complicated parts of SSR. An example of React InstantSearch and Next.js is available on our GitHub repository.

Did you find this page helpful?