Programmatic state update of <Configure /> breaks routing with React Router example

I’m trying to programmatically update the <Configure /> widget using properties like hitsPerPage and aroundRadius so a user can customize how many hits they see and the radius of those results.

To test this customization I’ve cloned the React Router example and made a few adjustments:

  1. I’ve created two buttons in my render() method to allow a user to change the hitsPerPage:
<button onClick={this.handleHits} value="10">Show 10 per page</button>
<button onClick={this.handleHits} value="30">Show 30 per page</button>
  1. I created a handleHits() method to pass the new value into the searchState. I first create a copy of the existing searchState with _.cloneDeep and then pass it all back to searchState:
handleHits(ev) {
  let myObj = cloneDeep(this.state.searchState);

  myObj.configure = {
    hitsPerPage: ev.target.value
  };

  this.setState({searchState: myObj});
}
  1. In order for React InstantSearch to pick this up, I pass the state back to <Configure />. I also run a few checks to ensure that the configure and hitsPerPage property exists.
<Configure
  hitsPerPage={
    this.state.searchState.configure &&
    this.state.searchState.configure.hitsPerPage ?
      this.state.searchState.configure.hitsPerPage : 30
  }
/>

Interacting with these buttons works as expected. However, the experience using the back/forward button is not working correctly. Here’s what occurs:

Back and forward buttons not working

You’ll see that clicking the back button (to go back to 10 results) works, but the forward button (to go to 30 results) is disabled.

Am I setting this up incorrectly? Perhaps there’s a better way to send custom data to <Configure /> to control things like aroundLatLng, aroundRadius, hitsPerPage, etc?

Hi @abushnell and thanks for the detailed explanation.

Along with this explanation, could you try to publish a live example using our React InstantSearch template on CodeSandbox? Then our React InstantSearch lead @samuel.vaillant will help you as soon as he is able to.

You bet, @vvo!

Unfortunately, I can’t reproduce this issue when I put the code into a CodeSandbox environment. Not entirely sure why that is! Maybe they run a React Router implementation that doesn’t exactly represent what a full browser is doing?

Anywho! I did create a repo of this issue so someone could clone and run it to see what is happening. Let me know if there are any additional questions or something you’d like to see! Appreciate the help here!

Hi @abushnell,

Thanks a lot for the example, it helps a lot.

The issue come from the fact that the value for hitsPerPage change between string and number across renders. Every time a render happens the <Configure> widget will do a shallow equal on previous and current props. If the props have changed the widget will schedule a new change. It means that the URL will be pushed multiple times, that’s why at some point it becames out of sync. You can solve this issue by always using the same type for the value of hitsPerPage. Here is a PR that update your example.

Note that the <Configure> widget is perfect for static values but for dynamic values the other widgets are more recommended. In your case, the usage of the connector connectHitsPerPage makes more sense. Here is a PR the implement the functionality with this component.

Hope that helps, let me know if you have questions.

This is fantastic! Thanks so much @samuel.vaillant!

I couldn’t find an aroundRadius connector to achieve the same strategy for a dynamic radius. Is it okay to pass dynamic radius values to <Configure /> as long as the types remain the same between renders?

Yes it’s definitely okay! You can find an example of that in our documentation, take a look at “Geo search using dynamic search parameters”.

1 Like

Awesome, thanks for the link!

Hey @samuel.vaillant, sorry to keep being a bother here. I have a dynamic radius control setup—I believe—the same way the aroundLatLng is setup. However using the back/forward buttons doesn’t seem to change my search results in the map.

I’ve created a CodeSandbox demo of this behavior which is a fork of the recipe you pointed me to.

If I click on different markers or change the radius via the buttons and use the back/forward buttons it changes the URL but it doesn’t seem to change what’s on the Google Map. Any ideas why this might be?