GithubHelp home page GithubHelp logo

Comments (23)

alexkirsz avatar alexkirsz commented on June 26, 2024 2

Ah yes, my bad. The add{Facet, DisjunctiveFacet} API hasn't made it in the helper yet.

For now, you should be able to do:

    searchParameters
      .setQueryParameters({
        facets: searchParameters.facets.concat(['category_slug', 'instock']),
        disjunctiveFacets: searchParameters.disjunctiveFacets.concat(['my_disjunctive_facet']), 
      });

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024 1

Makes sense now. Thanks!

from react-algoliasearch-helper.

alexkirsz avatar alexkirsz commented on June 26, 2024 1

Hey.

_.map(results.hits, (item, i)=> {
  return (
    <ProductTuple key={i} item={item} />
  );
})

In this context, results represents the search results of your initial helper. You'll need to create a new connected component that lives inside your ConnectedChildHelperProvider, so that it can receive the new results as props.

function MyCarousel({hits}) {
  if (!hits) {
    return null;
  }
  return (
    <Carousel settings = {data.CarouselSettings.tuples}>
      {
        _.map(hits, (item, i)=> {
          return (
            <ProductTuple key={i} item={item} />
          );
        })
      }
    </Carousel>
  );
}

const ConnectedCarousel = connect(state => ({hits: state.searchResults && state.searchResults.hits}))(MyCarousel);

And then:

<ConnectedChildHelperProvider
  configure={s => s
    .removeFacetRefinement("slug")
    .addFacetRefinement('category_slug', results.hits[0].category_slug)
    .addNumericRefinement('price', '>=', _.toInteger(results.hits[0].price * (1-0.05) ))
    .addNumericRefinement('price', '<=', _.toInteger(results.hits[0].price * (1+0.05)))
    .setQueryParameter('distinct', true)
  }>
  <Container>
    <Wrapper title="Similar Products">
      <ConnectedCarousel />
    </Wrapper>
  </Container>
</ConnectedChildHelperProvider>

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024 1

Wohoo! Works great!!! Thanks for the awesome support @vvo @Morhaus

from react-algoliasearch-helper.

vvo avatar vvo commented on June 26, 2024

Hi @harshmaur, can you provide us an example use case for that? Maybe explain here what you want to show as a web UI.

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024

I am using algolia's search to also populate my single page results. On every single page, I show a list of SAME products present on various eCommerce website to facilitate a price comparison.

Below the price comparison, I show similar products which needs another query.

Here is the ui for it.
page

from react-algoliasearch-helper.

vvo avatar vvo commented on June 26, 2024

@harshmaur You should be able to achieve this by having two helper instances and two Provider.

var mainHelper = helper();
var similarProductsHelper = helper();

mainHelper.on('change', function(state) {
  similarProductsHelper.setQuery(state.query).search();
});

const app = <div>
  <Provider helper=mainHelper/>
  <Provider helper=similarProductsHelper/>
</div>

(pseudo code)

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024

This would help me perform two queries however how do I access each state in my component? I am using connect as mentioned in #16 by @Morhaus

import {connect as reduxConnect} from 'react-redux';
import {connect as algoliaConnect} from 'react-algoliasearch-helper';

function mapAlgoliaStateToProps(state) {
    return {
      results: state.searchResults
    };
  }

const ReduxConnected = reduxConnect()(ProductSingle);

export default algoliaConnect(mapAlgoliaStateToProps)(ReduxConnected);

from react-algoliasearch-helper.

vvo avatar vvo commented on June 26, 2024

You will not be able to access both states in the same component at the same time, you will only always access one or another given where you put the Results component, see:

var mainHelper = helper();
var similarProductsHelper = helper();

mainHelper.on('change', function(state) {
  similarProductsHelper.setQuery(state.query).search();
});

const app = <div>
  <Provider helper=mainHelper>
    <Hits/> // have access to the state for mainHelper Provider
  </Provider>
  <Provider helper=similarProductsHelper>
    <Hits/>  // have access to the state for similarProductsHelper Provider
  </Provider>
</div>

Is that clearer?

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024

Hi @vvo I analysed my whole application and I see that having multiple providers will make structuring the application quite complex. For instance, I have been Adding the provider in my Root.js file wrapping all the components and containers inside it. Its very difficult to wrap a particular section of my container or the container itself.

Consider a scenario where I have the same similar products component twice on the same page. Now since the component is same the helper state will be the same however I want to be rendering different products inside of it and thus making two queries. Then i will have to create two separate components and reusability is lost.

I am not sure what is the best way to approach the problem.

from react-algoliasearch-helper.

vvo avatar vvo commented on June 26, 2024

@harshmaur You could then always have a single and create a custom widget that would connect to the query and use yourself either the https://github.com/algolia/algoliasearch-client-js or https://community.algolia.com/algoliasearch-helper-js/ to display hits from another index. This should work indeed.

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024

@vvo I could not understand. Which custom widget are you talking about? Also I do not see any query object available to me and I have one index only.

from react-algoliasearch-helper.

alexkirsz avatar alexkirsz commented on June 26, 2024

Hey.

I've written a small proof of concept for having a helper whose state is derived from another helper's state.

class ChildHelperProvider extends React.Component {
  constructor(props) {
    super();

    this.helper = algoliasearchHelper(client);
    this.updateState(props);
  }

  componentWillReceiveProps(nextProps) {
    this.updateState(nextProps);
  }

  updateState(props) {
    this.helper.setState(props.configure(props.searchParameters)).search();
  }

  render() {
    return (
      <Provider helper={this.helper}>
        {this.props.children}
      </Provider>
    );
  }
}

ChildHelperProvider.propTypes = {
  searchParameters: PropTypes.object.isRequired,
  configure: PropTypes.func.isRequired,
  children: PropTypes.node,
};

const ConnectedChildHelperProvider = connect(state => ({
  searchParameters: state.searchParameters
}))(ChildHelperProvider);

// Use it like this (where Results is a connected component):
<Provider helper={helper}>
  <div>
    <Results />
    {/* Also show results for the next page */}
    <ConnectedChildHelperProvider configure={s => s.setPage(s.page + 1)}>
      <Results />
    </ConnectedChildHelperProvider>
  </div>
</Provider>

The ChildHelperProvider component connects to the current helper's state, and creates a new helper with custom configured state that it exposes to its children. Every time the parent helper's state changes, the child helper's state will be changed as well and a new search will be triggered. You could also choose to listen directly on the helper's change and search events, but I've taken the simplest path.

Note that this child helper's state should not be modified directly. If you need to modify it, you should provide a new configure prop to the ChildHelperProvider.

Note also that the argument of the configure prop is a SearchParameters, not an AlgoliaSearchHelper, so the API slightly differs. The main difference between the two is that a SearchParameters is immutable, while a helper isn't.

@harshmaur Could that be useful in your case?

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024

Yes, I was able to do a second query properly however I am not able to access the new state inside the ConnectedChildHelperProvider.

My Container is like this. ProductSingle is already wrapped in the Provider from Root.js
I have created the ChildHelperProvider in another file and exported it.

class ProductSingle extends React.Component {

  constructor(props) {
    super();
    this.previousHelperState = props.helper.getState();
  }

  componentDidMount() {
    const {helper} = this.props;
    helper.setQueryParameter('distinct', false).search();
  }

  componentWillUnmount() {
    this.props.helper.setState(this.previousHelperState).search();
  }


  render(){
    let {results} = this.props;

    return(
      <div>

            {/* Comparison Data.. I get proper results from the first query */}

            {results.hits &&
              <Container>
                <Wrapper title="Compare Prices">
                  <CompareList data={results.hits} />
                </Wrapper>
              </Container>
            }

            {/*Similar Products... I dont get results from the new query in "results"  */}
            <ConnectedChildHelperProvider
              configure={s => s
                .removeFacetRefinement("slug")
                .addFacetRefinement('category_slug', results.hits[0].category_slug)
                .addNumericRefinement('price', '>=', _.toInteger(results.hits[0].price * (1-0.05) ))
                .addNumericRefinement('price', '<=', _.toInteger(results.hits[0].price * (1+0.05)))
                .setQueryParameter('distinct', true)
              }>
              <Container>
                <Wrapper title="Similar Products">
                  <Carousel settings = {data.CarouselSettings.tuples}>
                    {
                      _.map(results.hits, (item, i)=> {
                        return (
                          <ProductTuple key={i} item={item} />
                        );
                      })
                    }
                  </Carousel>
                </Wrapper>
              </Container>
            </ConnectedChildHelperProvider>
        </div>
      );
    }
  }
  ProductSingle.propTypes = {
    results: PropTypes.object,
    helper: PropTypes.object,
  };



  function mapAlgoliaStateToProps(state) {
    console.log(state.searchResults);
    return {
      results: state.searchResults
    };
  }


  const ReduxConnected = reduxConnect(null, null)(ProductSingle);

  export default algoliaConnect(mapAlgoliaStateToProps)(ReduxConnected);

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024

Instead of creating another component I am thinking of using contextTypes since I have already connected the ChildHelperProvider.

Here is my file.

import React, {PropTypes} from 'react';
import {Provider, connect} from 'react-algoliasearch-helper';
import algoliasearchHelper from 'algoliasearch-helper';
import algoliasearch from 'algoliasearch';


const client = algoliasearch('appID', 'key');


class ChildHelperProvider extends React.Component {



  constructor(props) {
    super();

    this.helper = algoliasearchHelper(client, 'indexname', {
      facets: ['category_slug', 'instock']
    });

    this.updateState(props);
  }


  getChildContext() {
    return {childResults: this.props.childResults};
  }

  componentWillReceiveProps(nextProps) {
    this.updateState(nextProps);
  }

  updateState(props) {
    this.helper.setState(props.configure(props.searchParameters)).search();
  }

  render() {
    return (
      <Provider helper={this.helper}>
        {this.props.children}
      </Provider>
    );
  }
}

ChildHelperProvider.propTypes = {
  searchParameters: PropTypes.object.isRequired,
  configure: PropTypes.func.isRequired,
  children: PropTypes.node,
  childResults: PropTypes.object
};

ChildHelperProvider.childContextTypes = {
  childResults: PropTypes.object
};

function mapStateToProps(state) {
  // console.log(state.searchParameters);
  return {
    searchParameters: state.searchParameters,
    childResults: state.searchResults && state.searchResults
  };
}

export const ConnectedChildHelperProvider  = connect(mapStateToProps)(ChildHelperProvider);

When I console.log the childResults I get the old state only. However my network tab shows there was a new search queried.

Moreover when I try to access it in my ProductSingle Container, my contextType childResults returns undefined. It should atleast give me results for the previous query since I can log that.

from react-algoliasearch-helper.

alexkirsz avatar alexkirsz commented on June 26, 2024

The ChildHelperProvider is connected to the old query, so it receives search parameters and search results from the old query. However, through the <Provider> it renders, it exposes new search parameters and new search results to its children. This is why you should make another connected component and render it inside your ChildHelperProvider.

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024

A new requirement has come up and I am unable to figure out again.

It is basically that I want to pass disjunctiveFacets from my first search to my childHelper. How can we do that?

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024

I have tried passing it as props to the constructor and instantiating the helper with disjunctive facets, however when I try to see the searchParameters of the new state in the child container, it shows the disjunctiveFacets that I have set for the main helper.

My constructor looks like this

constructor(props) {
    super(props);
    let disjunctiveFacets = [];
    if (props.disjunc) {
      disjunctiveFacets = props.disjunc;
    }

    this.helper = algoliasearchHelper(client, MAININDEX, {
      facets: ['category_slug', 'instock'],
      disjunctiveFacets : disjunctiveFacets
    });

    this.updateState(props);
  }

from react-algoliasearch-helper.

alexkirsz avatar alexkirsz commented on June 26, 2024

Hey.

You could do

<ChildHelperProvider
  configure={searchParameters =>
    searchParameters
      .addFacet('category_slug')
      .addFacet('instock')
      .addDisjunctiveFacet('my_disjunctive_facet')
  }
/>

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024

Hi,

Yes I can, but my problem is not that, if I am not wrong, .addDisjunctiveFacet would only work if I have mentioned that FacetFilter during initialisation of helper.

Currently my main helper does not have anything in disjunctiveFacets. However I want to add this to my second search.

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024

Works!!! Thanks a lot!

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024

Another Problem,

You mentioned earlier that, helper state from child container should not be modified directly, instead it should be done via configure props.

I have a usecase where I have to trigger a change in my helper when someone clicks on an item in my child container.

What is the best way to tackle this? Do you think I should use redux and create actions for it?

from react-algoliasearch-helper.

harshmaur avatar harshmaur commented on June 26, 2024

I figured, that I am not modifying the state, just making a .search or .getState.

from react-algoliasearch-helper.

Related Issues (8)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.