React-instantsearch: Prevent re-render when not necessary

Created on 23 Jun 2018  ·  6Comments  ·  Source: algolia/react-instantsearch

Feature: What is your use case for such a feature?

Don't re-render components when props + state don't change.

Feature: What is your proposed API entry? The new option to add? What is the behavior?

Use PureComponent for the components & returned widgets after being connected?

What is the version you are using? Always use the latest one before opening a bug issue.

5.1.0

Every component is re-rendered, every time. https://github.com/maicki/why-did-you-update makes this visible.

Thanks for your time!

❔ Question 🖥 Needs example

Most helpful comment

I think I've stumbled across this too - would you still like a test reproduction?

For anyone that runs into this - I removed 3 needless render() calls with the following:

// customHits.js

shouldComponentUpdate(nextProps) {
    if (this.props.hits.length !== nextProps.hits.length) {
      return true;
    }

    for (let i = 0; i < nextProps.hits.length; i++) {
      if (nextProps.hits[i].objectID !== this.props.hits[i].objectID) {
        return true;
      }
    }

    return false;
  }

All 6 comments

This could be a bug OR feature 😄

We already have a shouldComponentUpdate hook inside the function that creates the connector. Indeed the "view" components don't use shouldComponentUpdate or PureComponent. The latter won't avoid extra renders because most of the time props are not shallow equal. Most of the time it's completely fine to let React do the render.

Do you have any performance issue with React InstantSearch? If so please give us a reproducible example, it will help us to better understand where the issue come from. We provide template to avoid you the boilerplate part. You can find it on CodeSandbox.

Our use case is wrapping a Google maps component with the HitsConnector rendering the maps component alongside a location list component. The re-render is causing a flicker in the maps view even when the filtered list doesn't change. There's no state change in the controlling component to necessitate a re-render which led me down the path of the aforementioned utility to investigate.

Any ideas? Doing a deep comparison of props(hits) in shouldComponentUpdate? Thanks for the response!

Yes a possible solution is to implement a deep comparison inside shouldComponentUpdate. Is it possible to give us a small example of what you are trying to do? It will be easier to give you a more suitable solution. You can find a template on CodeSandbox. Thanks!

I think I've stumbled across this too - would you still like a test reproduction?

For anyone that runs into this - I removed 3 needless render() calls with the following:

// customHits.js

shouldComponentUpdate(nextProps) {
    if (this.props.hits.length !== nextProps.hits.length) {
      return true;
    }

    for (let i = 0; i < nextProps.hits.length; i++) {
      if (nextProps.hits[i].objectID !== this.props.hits[i].objectID) {
        return true;
      }
    }

    return false;
  }

You can do the same thing with a functional component using React.memo().

const AlgoliaHitsLoaderCached = React.memo(AlgoliaHitsLoader, (prevProps, nextProps) => {
    if (prevProps.hitsNeedLoading.length !== nextProps.hitsNeedLoading.length) {
        return false;
    }

    for (let i = 0; i < nextProps.hitsNeedLoading.length; i++) {
        if (nextProps.hitsNeedLoading[i].objectID !== prevProps.hitsNeedLoading[i].objectID) {
            return false;
        }
    }

    return true;
});

Note, my prop is based around hitsNeedsLoading as my component was loading additional information from the server based on the returned hits from algolia.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

noclat picture noclat  ·  3Comments

hatched-danny picture hatched-danny  ·  3Comments

vinhlh picture vinhlh  ·  5Comments

denkristoffer picture denkristoffer  ·  4Comments

flouc001 picture flouc001  ·  4Comments