Skip to content

[Feature] built-in debounce support on async select#3254

Closed
mmuller99 wants to merge 10 commits intoJedWatson:masterfrom
mmuller99:feature-debounceOnAsyncSelect
Closed

[Feature] built-in debounce support on async select#3254
mmuller99 wants to merge 10 commits intoJedWatson:masterfrom
mmuller99:feature-debounceOnAsyncSelect

Conversation

@mmuller99
Copy link

@mmuller99 mmuller99 commented Dec 5, 2018

#3075
Proposal

loadOptions is debounced by prop debounceInterval, minimizing unnecessary calls.
Initial load unaffected.

Example:

loadOptions only called after 250 milliseconds

<AsyncSelect 
      defaultOptions
      loadOptions={loadOptions}
      debounceInterval={250}
/>

@dustinsoftware
Copy link

@mmuller99 pretty cool, but this seems to introduce a new problem when mixing Async with Creatable: The "New entry" indicator flashes briefly before the search happens. GIF recording below:

react-select-async

@mmuller99
Copy link
Author

mmuller99 commented Dec 6, 2018

@dustinsoftware thanks for the feedback. I have a feeling its to do with "allowCreateWhileLoading", will have a look.

@mmuller99
Copy link
Author

mmuller99 commented Dec 6, 2018

So yes, setting

allowCreateWhileLoading={false}

stops the behaviour as expected. Not too happy with forcing to false on debounceInterval passed though

EDIT: Scratch that, seeing different things with different prop combinations. Will have a good look when I find time

@dustinsoftware
Copy link

dustinsoftware commented Dec 6, 2018

It looks like the problem can be avoided by debouncing the loadOptions method instead:

constructor(props: Props) {
	super();
	this.loadOptions = props.debounceInterval
		? debounce(this.handleLoadOptions, props.debounceInterval)
		: this.handleLoadOptions;
}

handleLoadOptions = (inputValue: string, callback: (?Array<*>) => void) => {
	// same method contents, but the method name is renamed to avoid confusion
};

handleInputChange = (newValue: string, actionMeta: InputActionMeta) => {
	// other logic
	this.setState(
		{
			inputValue,
			isLoading: true,
			passEmptyOptions: !this.state.loadedInputValue,
		},
		() => {
			this.loadOptions(inputValue, options => {
				if (!this.mounted) return;
				if (options) {
					this.optionsCache[inputValue] = options;
				}
				if (request !== this.lastRequest) return;
				delete this.lastRequest;
				this.setState({
					isLoading: false,
					loadedInputValue: inputValue,
					loadedOptions: options || [],
					passEmptyOptions: false,
				});
			});
		},
	);
}



render() {
	return (
		<SelectComponent
			// other props
			onInputChange={this.handleInputChange}
		/>
	);
}

@gsinovsky
Copy link

any chance on an update on this? glad to help if needed @mmuller99

@mmuller99 mmuller99 force-pushed the feature-debounceOnAsyncSelect branch from 4581fad to fe6838d Compare January 3, 2019 08:27
@mmuller99
Copy link
Author

mmuller99 commented Jan 3, 2019

@dustinsoftware thanks for the pointer, I debounced the loadOptions instead.

It's been expressed by the owner that he wants the debounce implementation left to the user here.

Maybe one of the collaborators can express their opinion on this PR?

BTW, @gsinovsky thanks!

@gsinovsky
Copy link

Hi @JedWatson, any chance on reviewing and merging this?

@mmuller99
Copy link
Author

@gwyneplaine any feedback?

@gsinovsky
Copy link

@JedWatson @mmuller99 still very interested in seeing this merged and published.

@gwyneplaine
Copy link
Collaborator

@mmuller99 definitely haven't forgotten about this PR, will be looking into this more deeply as part of our work to refactor async select. Will have a deeper look at this as soon as I have more time on my hands :) thanks for your patience

@chrysb
Copy link

chrysb commented Apr 19, 2019

Strong +1 to this feature request

@filippoitaliano
Copy link

There's a plan to merge this feature soon?

@ramospedro
Copy link

This is just what I need in my current project!
Any news on this?

@bluefire2121
Copy link

It's nearly November 2019...is there an update yet?

@gsinovsky
Copy link

gsinovsky commented Oct 29, 2019 via email

@changeset-bot
Copy link

changeset-bot bot commented Oct 29, 2019

⚠️ No Changeset found

Latest commit: df41e7f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@hnhegde
Copy link

hnhegde commented Nov 7, 2019

Any update on this PR? After using AsyncSelect, it is apparent that debounce must be a necessary accompaniment to AsyncSelect.

@JoeDuncko
Copy link

Any updates? This is 100% a required feature for async select.

@papaiatis
Copy link

papaiatis commented Jan 31, 2020

It's a long awaited async feature for react-select! Would be great to get it merged now.
@gwyneplaine could you post an update to this community please?

@bladey bladey linked an issue Jun 17, 2020 that may be closed by this pull request
@bladey bladey added pr/enhancement PRs that are specifically enhancing the project and removed category/enhancement labels Jun 24, 2020
Copy link

@zheskiel zheskiel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this feature is really needed

@codesandbox-ci
Copy link

codesandbox-ci bot commented Jul 7, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit df41e7f:

Sandbox Source
react-codesandboxer-example Configuration

@balazs-endresz
Copy link

FWIW, this can be also done currently with a function that takes a promise and returns a debounced promise (but not with any ordinary debounce functions): https://gist.github.com/balazs-endresz/c0c814a513724f44d90265422b9ae530 Call this outside a component or with useCallback and pass the result to loadOptions. And I think we've had issues with cacheOptions as well, so optionally this does something like that too.

@bladey bladey added pr/needs-review PRs that need to be reviewed to determine outcome and removed pr/needs-review PRs that need to be reviewed to determine outcome labels Aug 24, 2020
@khaphannm
Copy link

Any updates???????? Really needed :D

@dustinsoftware
Copy link

dustinsoftware commented Oct 13, 2020 via email

@Methuselah96
Copy link
Collaborator

Methuselah96 commented Nov 14, 2020

I've started a fork of react-select. Feel free to resubmit this PR on the fork and we can get it merged and released.

EDIT: 🎉 I've archived the fork now that we've got some momentum in this repo and Jed is involved again. Sorry for the disturbance!

@ochov1
Copy link

ochov1 commented Nov 26, 2020

#3075
Proposal

loadOptions is debounced by prop debounceInterval, minimizing unnecessary calls.
Initial load unaffected.

Example:

loadOptions only called after 250 milliseconds

<AsyncSelect 
      defaultOptions
      loadOptions={loadOptions}
      debounceInterval={250}
/>

this is not working at all, there is some other workaround?

@ebonow
Copy link
Collaborator

ebonow commented Jan 15, 2021

Greetings,

@JedWatson has expressed the following opinion #473 (comment)

Thanks for the PR but I'd prefer this was left for users to implement in the function that's passed to loadOptions

You can do this really simply by wrapping the method in lodash's debounce method (or similar) without adding any more logic to react-select

For those looking for a solution, please feel free to try the solution suggested here: #614 (comment)

const loadOptions = React.useCallback(
  debounce((inputValue, callback) => {
    getOptions(inputValue).then(options => callback(options))
  }, 500),
  []
);

return <AsyncSelect loadOptions={loadOptions} {...otherProps} />

Demo: codesandbox

@JedWatson
Copy link
Owner

Hey everyone, and thanks for the PR @mmuller99

Sorry for the lack of comms here, below is my response but I also want to acknowledge that this should have been said much earlier.

My view on this is that it is something you can (reasonably) easily do outside of react-select when you need it, and many libraries exist already specifically to make debouncing function calls easy.

As we've seen from the challenging history maintaining the library, even simple features add to the already huge surface area so the bar for inclusion of anything that can be done "in user-land" is really high.

However talking through it with @ebonow and @Methuselah96 in our maintainers sync this week, the combination of these points have gotten it over the line:

  • How often would you use Async and not want to debounce? It seems like the answer is "not often"
  • There is a really high level of community support for adding this
  • The additional feature is just scoped to the Async component

We're in the middle of our TypeScript conversion now (#4489) so this PR won't go in directly, but we'll backlog adding this for a post-5.0 release

@JedWatson JedWatson added after-typescript and removed pr/enhancement PRs that are specifically enhancing the project pr/needs-review PRs that need to be reviewed to determine outcome pr/priority PRs that should be addressed sooner rather than later labels Mar 25, 2021
@mmuller99
Copy link
Author

mmuller99 commented Apr 15, 2021

Thank you @JedWatson , appreciate the honest response and that native debounce, finally, has reached the roadmap.

@thinhbg2812
Copy link

Greetings,

@JedWatson has expressed the following opinion #473 (comment)

Thanks for the PR but I'd prefer this was left for users to implement in the function that's passed to loadOptions
You can do this really simply by wrapping the method in lodash's debounce method (or similar) without adding any more logic to react-select

For those looking for a solution, please feel free to try the solution suggested here: #614 (comment)

const loadOptions = React.useCallback(
  debounce((inputValue, callback) => {
    getOptions(inputValue).then(options => callback(options))
  }, 500),
  []
);

return <AsyncSelect loadOptions={loadOptions} {...otherProps} />

Demo: codesandbox

i tried this but, the options won't be re-render when the data is ready
any solution for this sir ?

@ebonow
Copy link
Collaborator

ebonow commented Nov 2, 2021

With version 5 out, I think we are in a position to pick this up if someone is willing to put in the work to have this work converted to the new TypeScript rewrite.

It seems reasonable that this is only applied to AsyncSelect and not Select correct?

@lvidal1
Copy link

lvidal1 commented Apr 7, 2022

Hi, is there any update on this?

@dcousens
Copy link
Collaborator

dcousens commented Oct 31, 2022

The pull request as written doesn't have consensus, and I think for now the recommendation of debouncing the loadOptions call yourself is transparent and straight forward for anyone to write themselves.

The feature isn't forgotten, but for now, I'm going to close this pull request.

@dcousens dcousens closed this Oct 31, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for debouncing filters