algolia / react-instantsearch

⚡️ Lightning-fast search for React and React Native applications, by Algolia.
https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/
MIT License
1.97k stars 386 forks source link

findResultsState doesn't return filtered data #2928

Closed lcnogueira closed 1 year ago

lcnogueira commented 4 years ago

Describe the bug 🐛 The data are not SSR when using findResultsState to load the filtered results at first rendering. It should behave like the available example here: https://react-instantsearch-algolia-nextjs.now.sh/, since I followed the provided nextjs example.

I have a search page where:

To Reproduce 🔍

I can provide a codesandbox example if it's necessary, but, If you don't mind, you can download the branch and easily test it by using my algolia credentials (it's used only for testing purposes).

Steps to reproduce the behavior: 1- Clone this branch: https://github.com/ufersa/plataforma-sabia/tree/feature/web/ssr-algolia-search 2- Include my credentials on a .env file inside the web folder:

ALGOLIA_SEARCH_KEY='e1b5eef00d6e629ce3a0dd50fdff074d'
ALGOLIA_APPLICATION_ID='N4XQK9NVKV'

3- Get in the web folder and install the dependencies: cd plataforma-sabia/packages/web && npm install 4-Run the project: npm run dev. 5-Paste the following URL directly into the browser: http://localhost:3000/search?query=nor&categories=agua

  1. See that the page doesn't load with the filtered results at first rendering. Actually, it loads all the hits (60), and, after that, it refines the search with the provided searchState.

Live example

  1. Paste the following URL directly into the browser: https://plataforma-sabia.herokuapp.com/search?query=nor&categories=agua (staging environment for testing)
  2. See that the page doesn't load with the filtered results at first rendering. Actually, it loads all the hits (60), and, after that, it refines the search with the provided searchState.

Expected behavior 💭 It should bring the filtered data from the server (5 hits in the case of the above example).

Environment:

Additional context

I've read the following related issues, but couldn't figure out what the problem is about: https://github.com/algolia/react-instantsearch/issues/1982 https://github.com/algolia/react-instantsearch/issues/2878 https://github.com/algolia/react-instantsearch/issues/1786

Haroenv commented 4 years ago

both here:

https://github.com/ufersa/plataforma-sabia/blob/feature/web/ssr-algolia-search/packages/web/components/MainSearch/MainSearch.js#L39

and here:

https://github.com/ufersa/plataforma-sabia/blob/feature/web/ssr-algolia-search/packages/web/components/Algolia/provider.js#L49

you need to spread props coming in from outside, or at least include onSearchParameters passed to InstantSearch from MainSearch. Without that the state will indeed be incorrect

lcnogueira commented 4 years ago

That's true! Thank you so much, @Haroenv . It works now!

I didn't notice it because there are some explicit props at the documentation example here, and the rest of them is spread. I thought those props were an example related to the user application. Maybe providing the prop explicitely would make it clearer.

        searchClient={this.props.searchClient}
        resultsState={this.props.resultsState}
        onSearchStateChange={this.props.onSearchStateChange}
        searchState={this.props.searchState}
        createURL={this.props.createURL}
        indexName={this.props.indexName}

        onSearchParameters={this.props.onSearchParameters}

        {...this.props}

btw, before opening this issue, I had seen another issue where you pointed this and, despite that, I couldn't figure out what the problem was. There is another case here.

It's a simple change but I think can help a lot. What do you think?

lcnogueira commented 4 years ago

Thanks, @Haroenv!

Haroenv commented 4 years ago

no problem at all :)

brideo commented 4 years ago

hey @Haroenv,

Sorry if I'm being dense, however, is there some documentation on where the onSearchParameters prop comes from? I can't see it in the index.js component in your next example.

For some reason I can't get findResultsState to return the correct data, also the searchState prop doesn't work for me either so I assume I am missing something, I have created a stripped down version here:

import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'next/router';
import algoliasearch from 'algoliasearch/lite';
import { findResultsState } from 'react-instantsearch-dom/server';
import MyInstantSearch from "../../components/Category/Algolia/InstantSearch";

const searchClient = algoliasearch(
    'foo',
    'bar'
);

const DEFAULT_PROPS = {
    searchClient,
    indexName: 'magento2_default_products',
};

class Category extends React.Component {

    static propTypes = {
        resultsState: PropTypes.object,
        searchState: PropTypes.object,
    };

    state = {
        searchState: this.props.searchState
    };

    static async getInitialProps() {

        let searchState = {
            hitsPerPage: 10,
            refinementList: {
                'categories.level0': ['Wipers']
            },
            hierarchicalMenu: {
                'categories.level0': 'Wipers'
            }
        };

        const resultsState = await findResultsState(MyInstantSearch, {
            ...DEFAULT_PROPS,
            searchState
        });

        return {
            resultsState,
            searchState
        };
    }

    onSearchStateChange = searchState => {
        this.setState({ searchState });
    };

    render() {
        return (
            <div>
                <MyInstantSearch
                    {...DEFAULT_PROPS}
                    resultsState={this.props.resultsState}
                    searchState={this.state.searchState}
                    onSearchStateChange={this.onSearchStateChange}
                />
            </div>
        );
    }
}

export default withRouter(Category);
import React from 'react';
import PropTypes from 'prop-types';
import {
    SearchBox,
    Configure,
    InstantSearch, Hits,
} from 'react-instantsearch-dom';

const HitComponent = ({ hit }) => (
    <div className="hit">
        <div className="hit-content">
            <div>
                <span>Category Level 0: {hit.categories.level0}</span>
            </div>
        </div>
    </div>
);

class MyInstantSearch extends React.Component {
    static propTypes = {
        searchState: PropTypes.object,
        resultsState: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
        onSearchStateChange: PropTypes.func,
        indexName: PropTypes.string,
        searchClient: PropTypes.object,
    };

    render() {

        return (
            <InstantSearch
                searchClient={this.props.searchClient}
                resultsState={this.props.resultsState}
                onSearchStateChange={this.props.onSearchStateChange}
                searchState={this.props.searchState}
                onSearchParameters={this.props.onSearchParameters}
                indexName={this.props.indexName}
            >

                {JSON.stringify(this.props.searchState)}

                <Configure hitsPerPage={5}/>

                <Hits hitComponent={HitComponent} />

                <SearchBox/>
            </InstantSearch>
        );
    }
}

export default MyInstantSearch;

OUTPUT:

{"hitsPerPage":10,"refinementList":{"categories.level0":["Wipers"]},"hierarchicalMenu":{"categories.level0":"Wipers"}}
Category Level 0: Ignition
Category Level 0: Filters
Category Level 0: Filters
Category Level 0: Filters
Category Level 0: Filters

References:

https://www.algolia.com/doc/api-reference/widgets/ui-state/react/?language=js

Haroenv commented 4 years ago

Hi @brideo, it seems like you're not forwarding the prop to MyInstantSearch, it needs to be forwarded all the way from findResultsState to the InstantSearch component. This does come back frequently, so I wonder if we can detect it somehow?

In our example we are spreading the props, so the issue isn't present by the way.

Reopening to find a location to warn in the library

brideo commented 4 years ago

hey @Haroenv ,

I actually think it was occurring because I didn't have a hierarchicalMenu component nested, sorry I should have replied.

But just to confirm, should I swap this:

onSearchParameters={this.props.onSearchParameters}

for a ...props spread?

I assume onSearchParameters is set by findResultsState then?

Haroenv commented 4 years ago

Actually I think I misread your example, and it should work fine. I'll still leave the issue open for the cases where onSearchParameters isn't being forwarded at all.

Widgets indeed need to be mounted for the search state to be taken in account.

Does it work for you now?

brideo commented 4 years ago

Yeah that works for me now, sorry I was removing stuff to try and find the issue and must have removed the widget, thanks for a quick reply.

If I was going to make a suggestion, I would improve the documentation of the onSearchParameters as I didn't really know where that was coming from.

Thanks for the examples though they are really good.

dhayab commented 1 year ago

Hi! We're doing a round of cleanup before migrating this repository to the new InstantSearch monorepo. This issue seems not to have generated much activity lately and the initial issue has been resolved, so we're going to close it. Feel free to open a new issue if necessary.