infinite loop when rendering a conditional loading message with children
See original GitHub issueDo you want to request a feature or report a bug?
Bug.
Bug: What is the current behavior?
(See below for full description.)
Attempting to use a connected “loading message” component (one that renders static content when loading and its children when finished) causes an infinite loop in certain circumstances.
- when
children
contains the<Stats />
component,searchResults.searching
is set as expected. - when
children
contains the<Hits />
and<Pagination />
components (possibly others),searchResults.searching
flips back and forth ad infinitum.
When the “loading message” component is configured to render static content upon completion, the infinite loop does not occur.
Bug: What is the expected behavior?
searchResults.searching
should not flip-flop between true
and false
in an infinite loop when rendering children
.
Bug: What browsers are impacted? Which versions?
Observed in Chrome 59.0.3071.109 & Safari 10.1.1.
What is the version you are using? Always use the latest one before opening a bug issue.
Observed in react-instantsearch 4.0.3 and 4.0.4.
Background
(copied/adapted from discussion on community forum.)
Using the example connector provided in your docs:
const connectLoading = createConnector({
displayName: 'ConditionalError',
getProvidedProps(props, searchState, searchResults) {
return {
loading: searchResults.searching
};
}
});
I then create a component that renders a message when loading, and its children when complete:
const LoadingMessage = connectLoading(({ loading, children }) =>
<div>
{loading ? <p>Loading...</p> : children }
</div>
);
Now we make use of it in a minimal UI where we just display the stats:
<InstantSearch ...>
<SearchBox />
<div className="SearchResults">
<LoadingMessage>
<p>FINISHED!</p>
<Stats />
</LoadingMessage>
</div>
</InstantSearch>
You can see this example here in a codepen: https://codepen.io/wrksprfct/full/jwmmox/
. This works as expected. Load the page and you see “Loading…” and then “FINISHED! X results found in Yms”. Ensure you have web console open and you’ll see the XHRs fly by and searchResults.searching
toggle between true
and false
when things change state. Type “avocado” into the box: the UI updates and the console logs as you’d expect.
Now here’s the fun part. Let’s replace the <Stats />
component with the <Hits />
component, so it looks like this:
<InstantSearch ...>
<SearchBox />
<div className="SearchResults">
<LoadingMessage>
<p>FINISHED!</p>
<Hits />
</LoadingMessage>
</div>
</InstantSearch>
You can see this example in another codepen: https://codepen.io/wrksprfct/full/yXbXNQ
. !!!BEWARE!!! before loading that page, be prepared to kill it via Chrome’s Task Manager or your OS’s equivalent because it gets into an infinite loop and consumes CPU & gobs of memory quickly. Again, ensure you have the web console open.
So, upon loading that page, you’ll see two XHRs instead of one (identical, AFAICT), and then searchResults.searching
flip between false
and true
ad infinitum.
If, in this problematic example, you hardcode the loading
prop to false
:
getProvidedProps(props, searchState, searchResults) {
return {
loading: false
};
}
…everything works. Well, except for seeing the loading message… which is the whole point of this exercise!
Again, the only difference is the switch from <Stats />
to <Hits />
. I looked at their sources, but could not find anything interesting.
Interestingly, the same problematic behavior occurs with <Pagination />
. See https://codepen.io/wrksprfct/full/zzzOWm/
. I did not test any others yet.
Now… if we update the LoadingMessage
component to not render children:
const LoadingMessage = connectLoading(({ loading }) =>
<div>
{loading ? <p>Loading...</p> : <p>DONE!</p> }
</div>
);
… then everything works fine:
<InstantSearch ...>
<SearchBox />
<div className="SearchResults">
<LoadingMessage />
</div>
</InstantSearch>
You can see this example in action in this codepen: https://codepen.io/wrksprfct/full/WOOajx
.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:11
- Comments:14 (4 by maintainers)
Top GitHub Comments
I had the same kind of issue with :
The workaround was to do :
💯
@blech75 @roma98 @reinvanimschoot
We are currently looking into the issue, we found where the problem came from. But for the moment we don’t have a proper fix. The problem is inherent of how React InstantSearch works. It’s related to how the query parameters are computed & the lifecycle of the components.
As a workaround for the example provided by @blech75 you need to avoid to mount / unmount the component on each change of the props
searching
. You can simply hide theHits
component with the help of styles instead of remove it on each changes. The fact that the component is mounted / unmounted trigger the infinite loop. I made an example showing how to avoid the problem with the workaround proposed above.