Server-Side Rendering | React InstantSearch V5 (Deprecated)
This version of React InstantSearch has been deprecated in favor of the latest version of React InstantSearch.
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.