React-instantsearch: "Error: [ssr]: no widgets were added " - A breaking change in v6.8.0, not properly documented.

Created on 17 Oct 2020  路  18Comments  路  Source: algolia/react-instantsearch

Describe the bug 馃悰

After updating to version v6.8.0 my code stopped working for SRR on NextJS. After digging in the PR's of this repository, I noticed that it is highly likely caused by pull request #2973, which was released a few days ago under v6.8.0.

I think this should have been marked as a breaking change. It changes the way SSR works using the WidgetsCollector which isn't properly documented in the documentation.

See SSR docs here.

The documentation shows that the <App /> component now receives a prop for widgetsCollector but this prop is never actually passed down by the server. Also, the related examples and type definitions were not properly updated, like the NextJS example.

To Reproduce 馃攳

Steps to reproduce the behavior:

  1. Run the NextJS example and open in your browser.
  2. It will popup the following error: Error: [ssr]: no widgets were added, you likely did not pass the `widgetsCollector` down to the InstantSearch component.

Expected behavior 馃挱

I expected this to be either backward compatible or released as a breaking change like the industry-standard semver suggests.

Environment:

  • OS: Linux
  • Browser: Chrome
  • Version: 36

Additional context

* For people running into the same problem *
I needed install and / or revert back and freeze the version of the packages react-instantsearch, react-instantsearch-dom and react-instantsearch-core to v6.7.0 in order to fix this problem. I specifically had to install react-instantsearch-core separately too and freeze at v6.7.0 because of react-instantsearch is set to resolve all "^6.7.0" (all 6.. versions), which means it will install the 'broken' version too, v6.8.0 and above. Installing and freezing the core package worked for me.

All 18 comments

Thanks for opening an issue, when I tried the example locally (and via the tests) it works without issue, as long as you spread the props in App towards InstantSearch. The goal is to replace the prop onSearchParameters with the prop widgetsCollector forwarded. I will look into this in detail and try to find the issue

You're right that this probably should have been a breaking change / major version

If you have a repo where it's not working as expected, that will help to see what's going wrong.

I think you might not spread the props as in the example, this works as expected for me: https://codesandbox.io/s/github/algolia/react-instantsearch/tree/master/examples/next?file=/components/app.js:1507-1525

EDIT the example on the repo wasn't updated yet, but it works when you update the dependency too https://codesandbox.io/s/gracious-mayer-6rrzy?file=/components/app.js

@Haroenv thanks for taking the time to debug this. I converted the above code sandbox to how I've set it up in my next.js project (with getServerSideProps instead of getInitialProps).

Here is my sandbox:

I just do not understand where widgetsCollector is coming from, if you follow it up the tree, it never gets assigned or passed down. If I comment it out from the <InstantSearch ...> component, you get the error mentioned in this issue.

Yet if you console.log the value of this.props.widgetsCollector, you get undefined. I simply do not understand where widgetsCollector is coming from, and why it works.

I'm confused, also the types in the @types package are missing so it's harder for me to pass down all the props into InstantSearch.

Does this help and could you explain what is going on?

--

I managed to fix the issue by extending the types of react-instantsearch-core like this:

(react-instantsearch-core.d.ts)

export declare module "react-instantsearch-core" {
  interface InstantSearchProps {
    widgetsCollector: any;
  }
}

And then actually passing the widgetsCollector from my search page props to the <InstantSearch> component, I'm still very confused on to why this works and where widgetsCollector is coming from, hope someone can explain!

I have the same problem

you seemed to have forgotten the actual sandbox, could you send it please? The typings are indeed not yet updated, since those are community maintained. I can review a PR to definitelyTyped though!

Here is the code sandbox: https://codesandbox.io/embed/cool-montalcini-lqyrj?file=/pages/index.js:2110-2123&codemirror=1

Thanks @ItsWendell, but what doesn't work about this? Just like onSearchParameters before, it's being set when you call findResultsState for determining which widgets render, so it's only used on the server; the logs you see are on the frontend :)

I've made a PR to definitelytyped for adding it to the typescript definitions

An update of the next example would help a lot, really have no clue on how to fix this.

@alexvandervegt I can seem like a bit of magic, but here's how I think it works.

In NextJS, since you pass down a NextJS Page during SSR to findResultsState, that will pass down the prop widgetsCollector to that page. Your <InstantSearch> component needs this prop during SSR to properly find widgets I guess.

It looks empty indeed in the client side since findResultsState only passes down this prop, simply adding the property widgetsCollector to the page and passing that down to my <InstantSearch> component fixed it for me.

Here's an small example:

// ...

export const SearchPage = ({
  searchState,
  resultsState,
  onSearchParameters,
  searchClient,
  widgetsCollector,  // Deconstruct or pass down all ...props
}) => {
  return (
    <InstantSearch
      searchState={searchState}
      resultsState={resultsState}
      indexName="companies"
      searchClient={searchClient || client}
      onSearchParameters={onSearchParameters}
      widgetsCollector={widgetsCollector}
    >
        <RestOfYourComponents />
    </InstantSearch>
  );
};

export const getServerSideProps = async ({ req, res }) => {
  const searchState = urlToSearchState(req.url || "");
  const resultsState = (await findResultsState(SearchPage, { // findResultsState adds widgetsCollector to the SearchPage
    searchClient: client,
    searchState: searchState,
    indexName: "your_search_index",
  }));

  return {
    searchState: JSON.parse(JSON.stringify(searchState)),
    resultsState: JSON.parse(JSON.stringify(resultsState)),
  };
};

Thanks, I have it working now!

However SSR side is working but how can we fetch the widgetsCollector client side?

widgetsCollector is _only_ used on the initial render server side, just like how onSearchParameters was :)

I also have the bug client side, see attached.

When i refresh the page the SSR renderer kicks in and everything is working.
Screenshot 2020-10-28 at 12 50 01

could you show this bug in a sandbox perhaps @alexvandervegt? This doesn't seem to happen with the demo: https://codesandbox.io/s/github/algolia/react-instantsearch/tree/master/examples/next?file=/pages/index.js

I got it working already, was a mistake on my side.

Were you calling findResultsState on the client too maybe?

yep...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

noclat picture noclat  路  3Comments

rtman picture rtman  路  5Comments

markmiller21 picture markmiller21  路  3Comments

oznekenzo picture oznekenzo  路  3Comments

aaronbushnell picture aaronbushnell  路  4Comments