On this page
Overview#
When using server-side rendering, instead of having your browser download a minimal HTML page that JavaScript will fill, the initial content is generated on the server. Then, the browser will download a page with the HTML content already in place. Usually server-side rendering is considered to improve SEO and performances.
React InstantSearch is compatible with server-side rendering. We provide an API that can be used with any server-side rendering solution.
Native#
We provide an API called createInstantSearch
, available at react-instantsearch-dom/server
.
When called, createInstantSearch
returns:
InstantSearch
: a component that accepts aresultsState
prop containing the Algolia results retrieved by the functionfindResultsState
.findResultsState
: a function to retrieve aresultsState
object. The function takes two arguments:- a component that contains the
InstantSearch
widget and all the widgets that have to be mounted on the page. - a
searchState
object for computing theresultsState
. Use it to pass a your initial state such as{ searchState: { query: 'chair' } }
. You’ll typically do this when dealing with URL sync and pulling the initial search query from the URL. Make sureApp
passes the initialsearchState
prop on to theInstantSearch
component too.
- a component that contains the
We split this guide into three parts:
App.js
is the server and browser shared main React component from your applicationserver.js
is a simple Node http server, it’s the main server entrybrowser.js
is the main browser entry that ultimately gets compiled tobundle.js
App.js#
App.js
is usually the main entry point of your React application, it exports an
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
import algoliasearch from 'algoliasearch/lite';
import React, { Component } from 'react';
import { createInstantSearch } from 'react-instantsearch-dom/server';
import { SearchBox, Hits } from 'react-instantsearch-dom';
const searchClient = algoliasearch(
'appId',
'apiKey'
);
// Now we create a dedicated `InstantSearch` component
const { InstantSearch, findResultsState } = createInstantSearch();
class App extends Component {
render() {
return (
<InstantSearch
indexName="indexName"
searchClient={searchClient}
searchState={this.props.searchState}
resultsState={this.props.resultsState}
>
<SearchBox />
<Hits />
</InstantSearch>
);
}
}
export { App, findResultsState };
Steps:
- Use
createInstantSearch()
to get afindResultsState
function and a dedicated<InstantSearch>
component (instead of importing the one underreact-instantsearch-dom
) - Export
<App>
(to be used by browser and server code) andfindResultsState
(to be used by server code)
Notes:
- Keep a reference to your dedicated
InstantSearch
component, do not re-create it at each render loop of yourApp
component (This will fail:... render() { return createInstantSearch(); }
) - If you want to use multiple
<InstantSearch>
components, then you need to create dedicated<InstantSearch>
components for each of them. - If you are syncing the searchState to the url for proper routing, pass a
searchState
to theInstantSearch
component.
server.js#
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 React from 'react';
import { createServer } from 'http';
import { renderToString } from 'react-dom/server';
import { App, findResultsState } from './App';
const server = createServer(async (req, res) => {
const searchState = { query: "chair" };
const resultsState = await findResultsState(App, { searchState });
const initialState = { searchState, resultsState };
const html = renderToString(<App {...initialState} />);
res.send(
`
<!doctype html>
<html>
<body>
<h1>Awesome server-side rendered search</h1>
<did id="root">${html}</div>
<script>window.__APP_INITIAL_STATE__ = ${JSON.stringify(appInitialState)}</script>
<script src="bundle.js"></script> <!-- this is the build of browser.js -->
</body>
</html>
`
);
});
server.listen(8080);
Notes:
- You have to transpile (with Babel for example) your server-side code to be able to use JSX and import statements.
__APP_INITIAL_STATE__
will be used so that React ensures what was sent by the server matches what the browser expects (checksum).
browser.js#
This is the last part that does the plumbing between server-side rendering and the start of the application on the browser.
1
2
3
4
5
6
7
8
import React from 'react';
import { render } from 'react-dom';
import { App } from './App';
render(
<App {...window.__APP_INITIAL_STATE__} />,
document.querySelector('#root')
);
Notes:
- A request will still be sent to Algolia when React mounts your
<App>
in the browser.
👌 That’s it! You know the basics of doing a custom server-side implementation.
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 here.
Next.js#
Next.js is a framework for React specifically wrapping and hiding some of the more complicated parts of SSR. An example of React InstantSearch and Next.js is available here.
The createInstantSearch
pattern#
It might be a bit confusing why we cannot use directly the <InstantSearch>
component you were previously using, this part details a bit why we took this approach.
React InstantSearch is a declarative API that programmatically builds an Algolia query. Based on every widget used, and their own options, we compute a set of parameters that should be sent to Algolia.
While doing browser rendering, we need to first render a Component tree alone (to compute every parameter) to then re-render it again with results. Unfortunately the React server-side rendering feature does not allow for such a pattern.
The only solution is to provide an API to get a set of results to then be passed down to an <InstantSearch>
component as a prop.
As this can be confusing, you might have better ideas on how we could have implemented this; if so, reach out on our GitHub or on our discourse forum.