Server-side rendered React apps using React InstantSearch 🎉

Hi there!

Today we are happy to announce that React InstantSearch is compatible with Server-side rendering. We just released a new set of API that can be used with any Server-side rendering solution such as Next.js. :rocket:

This feature is currently in beta (4.1.0-beta.1 as for now) and we’ll love to hear your feedback about it! We’ll continue to improve it until we hit a stable version.

To get you started we wrote a new dedicated guide that will take you through the main steps of the implementation.

We also wrote two new recipes:

Happy Coding!

5 Likes

Hi! This is really cool but I’m having trouble mapping your example onto our code base.

In your example, InstantSearch is in the top level component for the whole app. However, in our code base, the component containing InstantSearch is within many other components such as React Router, Material UI theme provider, etc.

This means that when InstantSearch tries to render this component in isolation server-side in order to get results, it throws errors (e.g. React Router Links can’t be rendered except inside a component). Is there an easy way to get around this?

Hi @Owen,
Can you provide me a simple example reproducing the trouble using CodeSandbox for instance? That way I could debug more easily :slight_smile:

Are you trying to use findResults with your whole app? Can you isolate the InstantSearch part and only use this one with it?

Thanks!

Hello. I’ve got React InstantSearch working with Next.js thanks to your example.

I’d like to run InstantSearch on a page that uses Next’s dynamic routing but I’m struggling with 2 things and wondering if anyone could help. It’s hard to explain so I’ve made an simple repo and deployed an example.

Repo here: https://github.com/lkbr/next-ris
Example here: https://create-next-example-app-tosvvlsxyd.now.sh/category/Lighting

I’d like to have a default refinement when a category page is loaded.

  1. I’ve tried using a virtual widget whos default refinement is the url query that Next exposes (see this commit). However the default refinement is only applied on the client and not the server. Refresh the example to see the “Lighting” refinement is not applied for a brief second. I’m sure its possible to use findResultsState() to do this but I am not sure how to. Which leads to the second issue I’m facing:

  2. A 404 error briefly flashes every time a refinement is made. This only happens on dynamic pages (e.g. category/:id). Go to the example and click any refinement. Notice the brief 404 flash after the refinement. I found, and posted on, what seems to be a related issue on Next: https://github.com/zeit/next.js/issues/2833

Personally, I’d be happy with just the default refinement applied without InstantSearches searchState to URL syncing (as I don’t like the messy urls) but its difficult to separate out the url syncing code from the your Next example.

Thanks in advance for any help.

Hi @ikbr,

Just to let know that debugging your issue will take me some time. I’ll get back to you as soon as I have an answer :slight_smile:

1 Like

I’m struggling to get this up and running in my app.

I’m getting the following error…

UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): TypeError: Cannot read property 'results' of undefined

I’m up to date using react-instantsearch 4.1.3.

I’m passing the promise returned from findSearchResults(App) as the results state prop.

Hi @andy.harl,

It seems that the promise failed, could you actually get the error message when the promise failed and copy paste it here :slight_smile: Thank you!

Hi @lkbr, we looked at your issue!

You can take a look at the solution on this Github issue.

Feel free to reopen it if needed :wink:

I’ve solved the issue I was having by using findResultsState() the way @samuel.vaillant demo’d on the Github issue.

I no longer have the second issue as I am not doing any URL syncing.

Many thanks @samuel.vaillant and @marielaure.thuret

1 Like

@marielaure.thuret Thanks for the quick response.

It looks like the promise is resolving correctly, but that when I set the results state as resultsState={this.props.resultsState || {}} like the demo shows the InstantSearch component tries to access results from an undefined object when the app first gets run through the findSearchResults function. Maybe I’m misunderstanding what is going on though.

I created a quick sandbox that shows the issue if that is helpful. https://github.com/aharl/dotnetcore-instantsearch-ssr

Hi @andy.harl,

Indeed, it seems that we don’t handle very well passing {} as resultState. I tried to debug within your project but didn’t manage to understand how modifying directly the node_modules could be taken into account. Maybe you have a hint there for me?

In any case, if you pass {} as a resultState, it’ll means that the results are going to be empty on the server and then the first payload will not be fully completed with results. Do you have a way on your side to not render the InstantSearch component until the findResultsState promise is resolved?

@marielaure.thuret Thanks for taking a look at the code. You might need to restart dotnet after editing the node modules directory directly. The App is set to startup a nodejs debugger as well. If you are using chrome then you should see the green node icon in the dev tools.

Either way, what I’ve seen is that if I pass the promise I get from findResultsState directly to the InstantSearch resultsState prop then it never resolves or I get an unhandled promise rejection error “can’t read property results on undefined” in the node debugger. The dotnet core app will timeout after 30s if a promise never resolves or rejects. I tried passing the response from the findResultsState promise (despite the published examples not showing that, but it looked like the decorateResults function in createInstantSearchServer.js might be looking for that rather than a promise ) and it doesn’t work either.

Big thanks for helping solve this.

1 Like