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

`createInstantSearchRouterNext` doubles refinement requests to the Algolia API

jmotes opened this issue Β· comments

πŸ› Current behavior

We've started using createInstantSearchRouterNext in our Next.js application to solve issues with back button navigation, but noticed our application has started querying the Algolia API 3 times for each refinement selection instead of just once.

This is concerning for us since we are already paying a significant amount of money for Algolia and don't want to see our costs tripled.

UPDATE: I've adjusted the props to DynamicWidgets as the docs recommend to reduce network requests, but still have two requests instead of just one like we had previously...

UPDATE 2: I've switched to using the RefinementList component directly, since that's closer to our application's implementation. Looks like we're still having 2 requests per refinement.

Minimal reproduction is here:

https://github.com/jmotes/algolia-next-router-duplicate-requests

πŸ” Steps to reproduce

  1. Clone https://github.com/jmotes/algolia-next-router-duplicate-requests
  2. npm install && npm run dev to launch the application
  3. Open http://localhost:3000/ in Chrome and bring up the browser network console
  4. Observe 3 http requests for every refinement selection

Live reproduction

https://codesandbox.io/s/github/jmotes/algolia-next-router-duplicate-requests

πŸ’­ Expected behavior

There should only be one network request with response containing items filtered by the selected refinement.

Package version

react-instantsearch-hooks-web 6.41.0, react-instantsearch-hooks-router-nextjs 6.41.0

Operating system

Windows 11

Browser

Chrome

Code of Conduct

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

Hey @jmotes,

You're passing a new instance of the algoliasearch client at every render, which is causing the issue. You need to instantiate the search client outside of your component so that InstantSearch reuses the same reference:

const client = algoliasearch('latency', '6be0576ff61c053d5f9a3225e2a90f76');

export default function Home() {
  // …

  return (
    <InstantSearch
      searchClient={client}
      indexName="instant_search"
      routing={{
        router: createInstantSearchRouterNext({ singletonRouter }),
      }}
    >
      {/* … */}
    </InstantSearch>
  );
}

Thanks so much @sarahdayan! I'm still learning React and sometimes forget that function references get destroyed on every render. In our actual implementation I can't hardcode the client, but I was able to utilize useMemo there to fix things up so there is only one request per refinement selection now!

I'm still seeing two requests on the initial page load that I was hoping this would fix too, but I'll debug more and create a separate issue for that if I can't resolve it.

@jmotes, why does the search client need to be conditional? We'd like to see if those use cases can be filled other ways too

@Haroenv our application is a Next.js renderer for WordPress's block editor, where the credentials are configured in WP and pulled in at runtime and the search functionality is implemented in a block that the user places on the page.

I was thinking I could instantiate the client in our global React Context and reference the context in the block's frontend component. But, we also have a site search that's always in the Header block and I wasn't sure it would make sense to share the searchClient between those two implementations since the search block placed on a page can be configured with different filters than the header search (so it's limited to show content for specific post types, etc.).

Not sure if I understand the use case completely, but the searchClient doesn't store any state, it's safe to share it across totally separate instances

@Haroenv oh ok! That was the part I wasn't certain about. I'll give it a shot!

@jmotes Regarding the two requests you see at initial page load, this might be an OPTIONS call and a POST call. Do you use Firefox?

@sarahdayan I'm using Chrome but looks like they are both POST requests.

But I just verified that is fixed in the minimal reproduction, so I probably just have another unstable React reference in our project somewhere. I keep thinking I've fixed them but I found another last night so probably another lingering one. If I can identify a way to reproduce it easily I'll create a new ticket and tag you both in it if that's ok!

image

@sarahdayan @Haroenv I figured what was causing the duplicate queries on page load and found a workaround so thought I'd post incase anyone else encounters this!

It only happens if Next.js middleware is in place. I think this bug explains why: vercel/next.js#38267

As I mentioned before, it was still happening when memo'ing the search client - which should have allowed us to handle the middleware re-renders issue, but my useMemo dependency array included an object that contained the app ID and public key. Breaking those out into scalars first allows React to more easily calculate that it doesn't need to re-create the search client on the re-render:

const { appID, indexName, publicKey } = algoliaCredentials;

const searchClient = useMemo(
	() => (appID && publicKey ? algoliasearch(appID, publicKey) : null),
	[appID, publicKey]
);

@Haroenv also, this does work great in our app's React Context - as long as it's memo'd. Thanks for the push in the right direction!

Perfect, in general the more things are static, the easier your app will be to reason about. We're trying to find ways to add more warnings if things people usually consider static aren't :)