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

DynamicWidgets does not work with Remix Link

dziugas-liaudinskas opened this issue · comments

🐛 Current behavior

When the component which is passed to the getServerState method contains DynamicWidgets and Link from “@remix-run/react” components it causes the app to break with the error: “useHref() may be used only in the context of a component.”. If DynamicWidgets or Link is removed then everything seems fine

🔍 Steps to reproduce

  1. Go to https://codesandbox.io/p/sandbox/lucid-cerf-glr0tu
  2. Everything should work fine, you can see filters and hits
  3. In app/components/Search.tsx change line 97 from <Hits hitComponent={Hit} /> to <Hits hitComponent={HitWithLink} /> (same component just wrapped with Link)
  4. "Error: useHref() may be used only in the context of a component."
  5. Now delete <DynamicWidgets>, refresh and the app is working again (just without filters)

Live reproduction

https://codesandbox.io/p/sandbox/lucid-cerf-glr0tu

💭 Expected behavior

DynamicWidgets should work with Remix Link

Package version

react-instantsearch-hooks-web 6.41.0, react-instantsearch-hooks-server 6.41.0

Operating system

macOS

Browser

Chrome

Code of Conduct

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

Hi, in getServerState() when we detect a dynamic widget we run renderToString on your search component a second time to get the initial state of all the dynamic facets we received from Algolia. This time, apparently the router context is lost, which creates the error you see.

We'll look at if and how we can fix that, but in the meantime, you can conditionally wrap your Hit component with a Link, depending on whether you detect a router context or not. Here's an example:

import { useInRouterContext } from 'react-router';

/* ... */

function HitWithLink({ hit }: HitProps) {
  const inRouterContext = useInRouterContext();
  const Hit = () => (
    <>
      <Highlight hit={hit} attribute="name" className="Hit-label" />
      <span className="Hit-price">${hit.price}</span>
    </>
  );

  if (inRouterContext) {
    return (
      <Link to="/new">
        <Hit />
      </Link>
    );
  }

  return <Hit />;
}