Query parameters disappearing after submitting the search box

Hello,

I am using Next.js with React InstantSearch Hooks , and I have encountered an issue with the search query disappearing from the URL after submitting the search box when transitioning from one page to another. This problem does not occur if I perform a search on the result page itself.

For example, when I press enter on the search box on ‘http://localhost:3000’, the home page, I am first redirected to ‘http://localhost:3000/results?query=edp’, but then the URL immediately changes to ‘http://localhost:3000/results’, causing the search query to disappear and the ui state to reset, the searchbox is empty. No 301 occur in the network tab.

Here is the routing configuration from my current _app.js implementation:

import { createInstantSearchRouterNext } from 'react-instantsearch-hooks-router-nextjs';
import { InstantSearch } from 'react-instantsearch-hooks-web';
import { searchClient } from '../lib/algolia/searchClient';
import { ClerkProvider } from "@clerk/nextjs";
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import { history } from 'instantsearch.js/es/lib/routers';

// other imports

function MyApp({ Component, pageProps, serverState, serverUrl }) {

  const router = useRouter()
  const { query } = router
  const routing = {
    router: history({
      windowTitle({ query }) {
        const queryTitle = query ? `Resultats pour "${query}"` : 'Recherche';

        return queryTitle;
      },

      createURL({ qsModule, location, routeState }) {
        const { origin, pathname, hash } = location;
        const indexState = routeState[process.env.NEXT_PUBLIC_ALGOLIA_DEALS_INDEX_NAME] || {};
        const queryString = qsModule.stringify(routeState);
  
        if (!indexState.query) {
          return `${origin}${pathname}${hash}`;
        }
        return `${origin}${pathname}?${queryString}${hash}`;
      },

      parseURL({ qsModule, location }) {
        const { query = '', brands = [] } = qsModule.parse(
          location.search.slice(1)
        );
        // `qs` does not return an array when there's a single value.
        const allBrands = Array.isArray(brands)
          ? brands
          : [brands].filter(Boolean);

        return {
          query: decodeURIComponent(query),
          brands: allBrands.map(decodeURIComponent),
        };
      },
    }),

    stateMapping: {
      stateToRoute(uiState) {
        const indexUiState = uiState[process.env.NEXT_PUBLIC_ALGOLIA_DEALS_INDEX_NAME]|| {};

        return {
          query: indexUiState.query,
          ...query
        };
      },

      routeToState(routeState) {
        return {
          [process.env.NEXT_PUBLIC_ALGOLIA_DEALS_INDEX_NAME]:  {
            query: routeState.query,
            ...query
          },
        };
      },
    },
  };

// ...

  return(
      <ClerkProvider
        {...pageProps}
        appearance={{
          elements: {
            socialButtonsBlockButton__google: {
              display: isFacebook ? "none" : "flex",
            },
          },
        }}
        localization={defaultResource} 
      >
        <InstantSearch
          searchClient={searchClient()}
          indexName={process.env.NEXT_PUBLIC_ALGOLIA_DEALS_INDEX_NAME}
          routing={routing}
        >
          <Component {...pageProps} />
        </InstantSearch>
      </ClerkProvider>
  )
}

export default MyApp

The results page is pretty basic:

// pages/results/index.js
export default function Index() {

  const { user } = useUser();
  const router = useRouter();
  const { query } = router;

  return (
    // ....
  )
}
```

Do you have any idea to solve this problem and maintain the uistate with the search query in the result page?

Thank you for you help.

1 Like

I have the exact same use case and exact same issue. I’d love to hear if anyone has figured this out.

1 Like

same issue, I’m using the Nextjs router package createInstantSearchRouterNext

<InstantSearch
  searchClient={searchClient}
  indexName={searchIndex}
  routing={{
    router: createInstantSearchRouterNext({
      singletonRouter,
    }),
  }}
    <SearchBox />
</InstantSearch>

I get this console warning


[InstantSearch.js]: The UI state for the index "themes" is not consistent with the widgets mounted.

This can happen when the UI state is specified via `initialUiState`, `routing` or `setUiState` but that the widgets responsible for this state were not added. This results in those query parameters not being sent to the API.

To fully reflect the state, some widgets need to be added to the index "themes":

- `query` needs one of these widgets: "searchBox", "autocomplete", "voiceSearch"

If you do not wish to display widgets but still want to support their search parameters, you can mount "virtual widgets" that don't render anything:

const virtualSearchBox = connectSearchBox(() => null);

search.addWidgets([
  virtualSearchBox({ /* ... */ })
]);

If you're using custom widgets that do set these query parameters, we recommend using connectors instead.

See https://www.algolia.com/doc/guides/building-search-ui/widgets/customize-an-existing-widget/js/#customize-the-complete-ui-of-the-widgets

Hi guys ,

@charles @dev28 @rob7
please refer to this you can find the solution or else you post your code in the stackblitz. so that i can fix it.

examples

for basic

  <InstantSearch
      searchClient={searchClient}
      indexName="instant_search"
      routing={true}
    >
      {/* ... */}
    </InstantSearch>

how to create url this helps you.

changing the state of the URL this can help you.

Implemented in Angular by me :

Has anyone been able to make this work with NextJS?

I am also having the issue that each new query input will set the URL and then reset it straight away.

Here is my code:

      <InstantSearch
        searchClient={searchClient}
        indexName={index}
        insights={true}
        routing={{
          router: createInstantSearchRouterNext({
            singletonRouter
          }),
        }}
      >
        <CustomSearchBar namespace={'actor'} />
        <SearchResult extended={extended} />
      </InstantSearch>