algolia / instantsearch

⚑️ Libraries for building performant and instant search and recommend experiences with Algolia. Compatible with JavaScript, TypeScript, React and Vue.

Home Page:https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/js/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SSR fails in next due to router.

b3nk3 opened this issue Β· comments

πŸ› Current behavior

Server-side rendering with React InstantSearch Hooks works fine when using useRouter in /pages up until next version 13.0.2

However anything above this seems to break the functionality.

πŸ” Steps to reproduce

  1. Open working sandbox: link and observe it working (/) character displayed from router.

  2. Open second sandbox (link below) with latest next version (13.4.4) and observe the complaint about router.

Live reproduction

https://codesandbox.io/p/sandbox/next13-4-4-wk6lj1

πŸ’­ Expected behavior

SSR works on latest next same as it does on 13.0.2

Package version

6.44.0

Operating system

macOS/Linux

Browser

all

Code of Conduct

  • I agree to follow this project's Code of Conduct

This error seems to be triggered by getServerState which is called "outside" the app and NextJS is getting stricter about that.

A possible workaround:

  const router = serverState ? useRouter() : {};

Having router undefined when getServerState is called is OK. getServerState is only interested in mounting Algolia widgets to retrieve the UI state before SSR. To quote the docs:

As an optimization you can pass a minimal version of the application that only uses the hooks of the widgets used in the search, with the same options.

@dhayab addresses it here #5475 (comment)

Yes, unfortunately there's no way for us to provide a fake router (Next doesn't export the Context), otherwise that would also be a workaround.

I solved this by just doing it manually and build up the serverState. This solves a whole bunch of issues with hooks that depend on next router or any other provider. It seems odd that this solution is not documented as its way easier then dealing with a "minimal version of your application" (good luck keeping that in sync).

import {
  InstantSearch,
  InstantSearchServerState,
  InstantSearchSSRProvider,
} from 'react-instantsearch-hooks-web';

const SearchPage = ({ serverState }) => {
  return (
     <InstantSearchSSRProvider {...serverState}>
       <InstantSearch indexName={indexName} searchClient={searchClient}>
          {/* Whatever you want here */}
       </InstantSearch>
     </InstantSearchSSRProvider>
  );
};

export default SearchPage;

export const getStaticProps = async () => {
  // index here is an instance of SearchIndex retrieved from `searchClient.initIndex`
  const searchResults = await index.search('', {
    hitsPerPage: 10,
    // Ensure you also fetch the facets and filters you need
    facets: ['city', 'experience.title'],
    filters: `startDatetime >= ${todayTimeStamp}`,
    maxValuesPerFacet: 10,
    page: 0,
  });

  // We mimic the initialResults so everything can be populated SSR
  const serverState: InstantSearchServerState = {
    initialResults: {
      [index.indexName]: {
        state: {
          facets: [],
          index: index.indexName,
          // Important to have the following 2 properties so useRefinementList items are populated correctly 
          disjunctiveFacets: ['city', 'experience.title'],
          disjunctiveFacetsRefinements: { city: [], 'experience.title': [] },
          // Again repeating the same data
          hitsPerPage: 10,
          maxValuesPerFacet: 10,
        },
        results: [searchResults],
      },
    },
  };

  return {
    props: {
      serverState,
    },
    revalidate: Duration.FIVE_MIN,
  };
};

The above is a lot easier to work with since its framework agnostic and contains less magic. IMO Algolia could wrap this in a little helper function which returns the correctly typed server state.

Hey @JanStevens - We've gone over to the App Router side and doing similar things using the JS SDK over their React one.

We are having the same issue with the latest version of the library