React-select: Fuzzy match, (potentially) expose matching algorithm, perf, styling, async API, etc.

Created on 1 Apr 2015  路  6Comments  路  Source: JedWatson/react-select

(I understand if this isn't a big concern right now)

sou should probably match South Australia. Basically, fuzzy search that matches substrings (I keep forgetting the actual name of this), or conceptually adding .* after each letter in the search query regex.

API concerns

You can probably just expose a prop filterFunc f(query, potentialMatch): bool, with a sane default being the current internal filterOptions (maybe exported as ReactSelect.defaultFilter or simply used as the default value of filterFunc). Fuzzy match libraries are available everywhere, but you can also export a ReactSelect.fuzzyFilter, or not. This allows you to eliminate the library-specific matchPos prop in exchange for something agnostic, much more flexible (better user-made fuzzy match, match/do not match non-ascii chars, blabla) and equally clean.

Abstraction 1

(If the above one sounds realistic)
Instead of the above, expose filterFunc as f(query): [String]. The function takes the query and returns a list of matches. This eliminates the seemingly necessary options props and gives you even more flexibility (dynamically changing list of options through if-elses in the callback). If you want to further reduce API surface, accept f(query): Promise [String], which is intended for async loading of options and/or match results. Kills asyncOptions.

Abstraction 2 (getting hardcore lol)

Built on top of either the original proposal or the previous one, if the latter makes sense. Say we use the latter. Change filterFunc to f(query): [ReactNode]. Solves #5. Solves potentially other styling issues that you'll otherwise need to expose as additional options (and it's hard to cover all the use-cases). Ultimate API would be f(query): Promise [ReactNode].

Perf concerns

Better perf tuning. The default is still the internal filterOptions. Except now the user will able to fine-tune it. E.g. smaller list? Use the best fuzzy match + frecency + levenshtein distance algorithm you got. Bigger list? Use a variation of default algorithm + caching.

Abstraction 1

Optional options caching is done by the user, by simply lifting the inline options list inside f into the upper scope (or use a transformer). Same for cached results. This isn't important; just mentioning it for completeness.

Abstraction 2

Allows user to use either classes or inline styles. Latter for API niceness, former for historical reasons or perf.

categorquestion

Most helpful comment

For anyone else who comes across this issue and thinks its unresolved/not supported, it is actually perfectly doable today with the filterOptions parameter by passing a function....

I did fuzzy search with Fuse.io like this:
```
filterOptions() {
return function (options, filter) {
var fuseOptions = {
shouldSort: true,
tokenize: true,
threshold: 0.6,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [
"label"
]
};
var fuse = new Fuse(options, fuseOptions);
return fuse.search(filter);
}
}
...
render() {
return (
name="form-field-name"
value={ this.state.localId }
onChange={ this.mkHandleChange(onAnswer()) }
filterOptions={this.filterOptions()}
options={ options }
placeholder={placeholder}
/>
);
}
};

All 6 comments

I agree with this change, this and several other issues around functionality like this might indicate that we might need to design a simpler, more powerful API for react-select.

For anyone else who comes across this issue and thinks its unresolved/not supported, it is actually perfectly doable today with the filterOptions parameter by passing a function....

I did fuzzy search with Fuse.io like this:
```
filterOptions() {
return function (options, filter) {
var fuseOptions = {
shouldSort: true,
tokenize: true,
threshold: 0.6,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [
"label"
]
};
var fuse = new Fuse(options, fuseOptions);
return fuse.search(filter);
}
}
...
render() {
return (
name="form-field-name"
value={ this.state.localId }
onChange={ this.mkHandleChange(onAnswer()) }
filterOptions={this.filterOptions()}
options={ options }
placeholder={placeholder}
/>
);
}
};

quick note, there is no filterOptions in version 2

Any way to do fuzzy matching with version 2?

@bbigras @theluk

This is a working solution for v2: https://github.com/JedWatson/react-select/issues/3067#issue-363771398

Version 1 of react-select is no longer supported.

In the best interest of the community we've decided to spend the time we have available on the latest version.

We apologise for any inconvenience.

Please see:

  1. v1 to v2 upgrade guide
  2. v1 documentation and examples
Was this page helpful?
0 / 5 - 0 ratings

Related issues

pablote picture pablote  路  3Comments

MalcolmDwyer picture MalcolmDwyer  路  3Comments

pgoldweic picture pgoldweic  路  3Comments

batusai513 picture batusai513  路  3Comments

mbonaci picture mbonaci  路  3Comments