React-select: slow with large lists

Created on 28 Jan 2016  Â·  21Comments  Â·  Source: JedWatson/react-select

Hey - I'm using react-select with a list of 2500 elements. I find the box to be slow, especially when i'm deleting characters. Is there a more efficient way of managing a large list in react-select?

Most helpful comment

Is there a solution to increase performance for version ^2.0?
(react-virtualized-select and react-select-fast-filter-options seem to still work with 1.0)

All 21 comments

I also have the same problem. I think there should be a way to buffer a long list (similar to the solution used in some grid components, where only the rows that are effectively on the screen are rendered).

Same here. I have an list of around 1200 element, and the select2 component is lagging when scrolling and hovering on select2 items.

I ended up filtering the list via loadOptions={that.getOptions} where getOptions was

getOptions: function(input, callback) {
    var that = this;

    if (input.length > 0) {
        var searchString = input.toLowerCase().trim();
        var options = that.state.options.filter(function(d) {
            return d.query.match( searchString );
        });
    } else {
        var options = "";
    }
    return (
        callback(null, {
            options: options.slice(0, 10)
        })
    );
},

where each element in options has a well-defined "query" string
This ends up being insanely fast

Check out PR #859 (and the demo linked) which adds react-virtualized support.

Update: If you're able to use react-select 1.0.0 beta, then you might be interested in trying a new HOC, react-virtualized-select. Does windowing/lazy rendering so it should help with the issue you're reporting.

Chiming in after some time.

I _think_ this problem (slow filtering) comes down to how filtering is done within react-select (aka synchronously, in the UI thread. For large lists, this approach is going to hurt FPS.

I've created some JS search libs (eg js-worker-search, redux-search) that manage filtering in web-workers, using data structures optimized for fast look-up, and the response time for filtering drop-down lists using them is _very fast_.

Perhaps that would be interest in trying to integrate one of these libs with react-select? Perhaps even as an external HOC (similar to react-select-virtualized) that just exported a filterOptions function that could be passed as a prop to override the built-in react-select filter.

If there's interest, I would be happy to take a stab at it. Let me know!

To add a little more context...

I like using high-order components for this sort of functionality because (a) it doesn't bloat or add complexity to the underlying library (react-select) and (b) it lets users opt-in if they need the functionality. Lots of users just want a simple, styled drop-down menu and vanilla react-select works fine for that.

I was tentatively thinking of creating another light-weight lib that connects js-worker-search and react-select so people wanting to filter large lists of options could use _that_ library as their filterOptions property. So basically something like this...

import React from 'react'
import VirtualizedSelect from 'react-virtualized-select'
import fastFilterOptions from 'react-select-fast-filter-options'

function MyComponent () {
  return (
    <VirtualizedSelect
      {...props}
      filterOptions={fastFilterOptions}
    />
  )
}

New high-order component available to hopefully speed things up a lot!

Demo available here with 100,000 options: https://bvaughn.github.io/react-select-fast-filter-options/

Source and installation instructions here: https://github.com/bvaughn/react-select-fast-filter-options

Going to close this issue since react-select-fast-filter-options provides a lightweight way to improve filtering performance. I briefly considered making it the _default_ filterOptions implementation within react-select (and may still at some point) but didn't want to pull in the extra dependency on js-search for users with small options lists and simpler use-cases.

I've added a new section to the README making mention of this new library. Since I own react-select-fast-filter-options and js-search and I'm a collaborator on react-select as well- it should be easy to keep these libraries in sync going forward.

@bvaughn is there an update to your solution? Your demo seems to be broken.

Your demo seems to be broken.

In what way? Demo works for me.

@bvaughn It seems scrolling through causes an error passed 40 entries. Issue appears to be on official documentation as well #1438

@bvaughn Sorry for the confusion. I was looking at https://bvaughn.github.io/react-select-fast-filter-options/

It seems your demo at http://bvaughn.github.io/react-virtualized-select/ works just fine.

Interesting. Could not repro that error with my local build but I _did_ see it on the site. Rebuild and redeployed. Maybe a transient issue with dependencies. Soon as the cache clears it should be fine.

Is there a solution to increase performance for version ^2.0?
(react-virtualized-select and react-select-fast-filter-options seem to still work with 1.0)

I ended up creating my own component to handle this situation with something like this:

import React, { Component } from 'react'
import Select from 'react-select'
import { filter } from 'lodash/fp'

class LargeSelect extends Component {
  constructor(props){
    super(props)
    this.state = {
      inputValue: this.props.inputValue || "",
      displayedOpts: this.props.allOpts.slice(0, this.props.maxDisplayed),
    }
    this.handleInputChange = this.handleInputChange.bind(this)
  }
  handleInputChange(inputValue) {
    const displayedOpts = filter(
      ({label}) => label.toLowerCase().includes(inputValue.toLowerCase()),
      this.props.allOpts,
    ).slice(0, this.props.maxDisplayed)
    this.setState({inputValue, displayedOpts})
  }

  render(){
    return (
      <Select
        isMulti
        options={this.state.displayedOpts}
        onInputChange={this.handleInputChange}
        onChange={this.props.onChange}
        value={
          filter(
            ({value}) => this.props.value.includes(value),
            this.props.allOpts,
          )
        }
      />
    )
  }
}

LargeSelect.defaultProps = {
  onChange: () => {},
  maxDisplayed: 20
}

export default LargeSelect

Your demo seems to be broken.

In what way? Demo works for me.

It can not load react-select.css from
https://unpkg.com/[email protected]/dist/react-select.css

@bvaughn Is there a version of react-fast-filter-options for react-select v2? I need the flexibility of v2, such as the menuIsOpen prop. Thanks!

Don't know. I've never used v2, sorry!

so sad. I assume you've stopped using this library altogether? It just
seemed really hard to customize in the first iteration, so I want to use
v2.

On Tue, Nov 27, 2018 at 10:24 AM Brian Vaughn notifications@github.com
wrote:

Don't know. I've never used v2, sorry!

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/JedWatson/react-select/issues/739#issuecomment-442098499,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AZHNAX0ZWvXjTSRkycxjoEbXw7S-1rohks5uzVk8gaJpZM4HN_JB
.

--
Will Borwegen

I ended up filtering the list via loadOptions={that.getOptions} where getOptions was

getOptions: function(input, callback) {
    var that = this;

    if (input.length > 0) {
        var searchString = input.toLowerCase().trim();
        var options = that.state.options.filter(function(d) {
            return d.query.match( searchString );
        });
    } else {
        var options = "";
    }
    return (
        callback(null, {
            options: options.slice(0, 10)
        })
    );
},

where each element in options has a well-defined "query" string
This ends up being insanely fast

mind if i ask you to show me your
select component

Was this page helpful?
0 / 5 - 0 ratings

Related issues

x-yuri picture x-yuri  Â·  3Comments

AchinthaReemal picture AchinthaReemal  Â·  3Comments

juliensnz picture juliensnz  Â·  3Comments

joshualimpj picture joshualimpj  Â·  3Comments

steida picture steida  Â·  3Comments