Roger Johansson
Roger Johansson

Reputation: 23214

Extremely slow React list render

We are experiencing some frustrating issues with React. We have a form, consisting from a search form and a search result list. As seen below in the code. filter and content.

Whenever the user types in the search field, there is a debounce and a call to a rest service.

The result then populates the search result (content)

Even with as little as 15 items in the list, this is insanely slow. it takes about 300 ms per update. In production mode, there is no issue. only in dev mode. Also, removing propTypes makes it much faster but still slow.

We can see that the ContactSearchResultLayout is being rendered 3 times per keystroke, while it really just should care about the result of the rest call.

What are our best bets here? is the container component kind of pattern here wrong for our usecase, does it mean that if something in the SearchPageLayout props changes, the entire list will also be re-rendered?

We have a version that pretty much bypass React and just render item by item as they come in from the service call. Which is super fast, but on the other hand, much less maintainable.

Is there some idiomatic way to make this work with React?

<SearchPageLayout
  filter={
    <ContactSearchForm
      allTeams={allTeams}
      allAreasOfExp={allAreasOfExp}
      allResponsiblePeople={allResponsiblePeople}
      allTags={allTags}
      detailed={props.searchFormExpanded}
      onSearchFieldBlur={() => props.setSearchFormExpanded(false)}
      onSearchFieldFocus={() => props.setSearchFormExpanded(true)}
    />
  }
  content={
    <ContactSearchResultLayout       //<-- this rerenders too often
      items={items.map(item => (
        <ContactCard
          key={item.PersonId}
          areasOfExpertise={item.AreasOfExperise}
          cellPhone={item.CellPhone}
          city={item.City}

One reason for this as I see it, is that items is the result of a map operation and thus, causes a new array of components to be generated. But how do we bypass this?

Thoughts?

Upvotes: 3

Views: 8400

Answers (1)

Tzook Bar Noy
Tzook Bar Noy

Reputation: 11677

Anonymous function will get rendered each time.

I'll create another method for creating the items:

getItems() {
    return (
       items.map(item => (
        <ContactCard
          key={item.PersonId}
          areasOfExpertise={item.AreasOfExperise}
          cellPhone={item.CellPhone}
          city={item.City}
          />
       )
    )
 }

<ContactSearchResultLayout       
  items={this.getItems()} 
   />

How to check if props change and if you should re-render the code:

you can use react "shouldComponentUpdate" https://reactjs.org/docs/react-component.html#shouldcomponentupdate

componentWillUpdate(nextProps, nextState) {
    //here you can compare your current state and props
    // with the next state and props
    // be sure to return boolean to decide to render or not
}

Upvotes: 1

Related Questions