I want to reload default async options , when use enter some data in other part of app,but I do not know how to force reload of options.
+1
Any update on this?
I have a dropdown for country which then determines the Async.Select "options".
Change function for the country select reloads the options for the Async location select.
_handleChange_country() {
if (this.refs.country.value != this.state.country) {
this.setState({
country: this.refs.country.value,
location_value: []
})
this.refs.bob.loadOptions('')
}
}`
//// Inside render()
<select
ref="country"
value={this.state.country}
onChange={this._handleChange_country}>
.....snip options...
</select>
<Select.Async
ref="bob"
multi={true}
placeholder={this.props.search_placeholder}
value={this.state.location_value}
onChange={this._handleChange_location}
loadOptions={this._getLocationOptions.bind(this)}
valueKey='value'
labelKey='label'
autoload={false}
cache={false}
>
Apart from hacking with reference, is there a cleaner / built-in way to handle a refresh?
I'm not aware of any way at the moment. What is being asked for is a way to force a refresh of the options based on something else in an application changing (which could be a lot of things).
Only option I can think of is to have a listener of some sore on that something that then calls this.refs.bob.loadOptions('') to refresh bob's options. Or inbuilt into the Select.Async application to run "loadOptions('')" when it receives a new prop. That's if anyone out there wants to try and modify Select.Async to have a refresh options option.
Any update on this?
any update on this?
With the latest version.
I have a react component that use AsyncSelect, latest version has changed a bit.
In this I have a clearValues function. In the component that has all the other form controls, I call the clear values function when I need to reset the values of the Async Select.
_handleChange_country(event) {
this.refs.async_location_select.clearValues()
this.setState({
country_eq: this.refs.country.value,
})
}
clearValues = () => {
this.refs.async.select.state.value = ''
}
In the render AsnycSelect_Location_Component
<AsyncSelect
ref = 'async'
noOptionsMessage = { () => 'Type in location' }
styles = { customStyles }
placeholder = 'Enter city, state or postcode'
isMulti
cacheOptions
loadOptions = { this.loadOptions }
defaultOptions = { false }
onInputChange = { this.handleInputChange }
onChange = { this.trackChanges }
defaultValue = { this.props.defaultValue }
components = {{ LoadingIndicator, DropdownIndicator, Input }}
/>
why doesn't it just reload if loadOptions
changes? seems like that would be simple enough, just check on componentWillReceiveProps
@alexfoxgill LoadOptions is also a promise or callback. It loads the values displayed for the user to select from, not what they have already selected. What's being asked here is to clear what has already been selected. So in this case load options is not changed at all.
i think we have our wires crossed. i want to use the component like this:
interface Props {
externalValue: string
value: string
}
interface State {
loadOptions: (search: string) => Promise<string[]>
}
class MyComponent extends React.Component<Props, State> {
constructor(props: Props) {
super(props)
this.state = {
loadOptions: (search: string) => callExternalApi(props.externalValue)
}
}
componentWillReceiveProps(newProps: Props) {
if (newProps.externalValue !== this.props.externalValue) {
this.setState({
loadOptions: (search: string) => callExternalApi(newProps.externalValue)
})
}
}
render() {
return <AsyncSelect
value={this.props.value}
loadOptions={this.state.loadOptions} />
}
}
do you see? loadOptions
should reload whenever the function changes
My bad I was thinking of something completely different. In the case here its a externalValue prop that is changing not the function, the function is then meant to receive a different value. Unless you changed the actual function name or something.
when externalValue
changes, the this.state.loadOptions
function is recreated. this means it is a different object reference and can be compared by the component
This works for me:
<Async
key={JSON.stringify(this.state.someUpdatedProp)}
...
/>
Example working: https://github.com/helmarjunior/react-hooks-select-async
@helmarluiz that works well, thanks!
This does not work when a truthy isMulti
property is passed.
This works for me:
<Async key={JSON.stringify(this.state.someUpdatedProp)} ... />
how to you do this, as i want to update the options with the user input when serachable={true}
but when i use key, it closes after user type a letter
I have also applied the hack from @helmarluiz for now but I don't understand why the cacheOptions object doesn't already handle this as it appears to be what it is for.
The documentation is a little misleading:
/* If cacheOptions is truthy, then the loaded data will be cached. The cache
will remain until cacheOptions
changes value.
Default: false. */
If the cacheOptions is set to false this does not stop the cache being populated. (The opposite of if truthy the loaded data is cached) it only affects whether the cache is reset when the value changes.
If you provide an object and it changes it says it will clear the optionCache but it does not take into account the defaultOptions being set to true and reload them in this case.
I would like to see a native solution to this issue as it appears to be one a lot of people are suffering from... or guidance on how we should natively force the defaultOptions to reload based on external props in our own component.
The most common situation for this in our app is that we are using AsyncSelect to load all options and then filtering them based on what is in another array. When this array changes we need the options to reload and be re-filtered.
Adding optionCache={this.props.items} does not appear to work as even if the existing cache is cleared the loadOptions promise is not re-called to re-populate the options so they can be re-filtered.
@JedWatson Please can you advise how this workflow is supposed to be handled natively by the latest version of your async component?
hack from @helmarluiz works for me, thanks for that! Anyway there should be some other option to force reload default options ... definitely - this state is not sufficient.
for anyone using isMulti like me (@Steague for example), my workaround was to use a combination of local state and componentDidUpdate to manually set defaultOptions (it also accepts array of objects, instead of just boolean), whenever a property changes.
@helmarluiz 's method worked for me as well. Just for the record, my use case was that I fetch the options for the select on page load, but since the select starts disabled, it doesn't load the options. So once it gets enabled, I fetch the options again (it can start enabled depending on previous form values, that's why I fetch it twice) and reload it to display them.
I see a refreshToken
prop has been added stating :
_"If refreshToken is set and defaultOptions is truthy, All options will refreshing when refreshToken is changed."_
Anyone can provide a small example of this please ?
Trying to make it work in an "Async isMulti" scenario.
thank you @helmarluiz key did trick for me. otherwise it was sometimes loading defaultValue and sometimes not. very very frustrating!!
PS: i don't see anywhere "refreshToken" as mentioned in prev comment
@oudoulj, that fix is not merged yet. Would be great if it can get merged soon.
Any update on this? :)
As @Steague mentioned, the key=
hack from @helmarjunior and here from @kinyat does not work when using a truthy isMulti
property.
I found another hack here but couldn't get it to work.
I'm surprised React-Select doesn't have an official way of handling this desired functionality.
Below is my attempt at using regular Select (not async) as encouraged here. It loads and works correctly for the first tag, but when I try to add a 2nd tag, I see no options.
import React, { useState, useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import makeAnimated from 'react-select/animated'
import Select from 'react-select' //https://react-select.com/home
import { getTagCounts } from '../temp/api'
import { fetchFilteredPosts } from '../actions'
import { customStyles, formatOptionLabel } from './BaseAutocomplete'
const animatedComponents = makeAnimated()
const TagsAutocomplete = ({ placeholder }) => {
const dispatch = useDispatch()
const [tagOptions, setTagOptions] = useState([])
const [searchTerm, setSearchTerm] = useState('')
const posts = useSelector((state) => state.db.posts)
const tagCounts = getTagCounts(posts, searchTerm)
useEffect(() => {
setTagOptions(tagCounts)
}, [posts])
const handleChange = (newValue, actionMeta) => {
console.group('Value Changed')
console.log(newValue)
console.log(`action: ${actionMeta.action}`)
const tags = newValue ? newValue.map((tagOption) => tagOption.label) : []
dispatch(fetchFilteredPosts({ tags: tags }))
console.groupEnd()
}
const handleInputChange = (inputValue, actionMeta) => {
console.group('Input Changed')
console.log(inputValue)
setSearchTerm(inputValue)
console.log(`action: ${actionMeta.action}`)
console.groupEnd()
}
return (
<Select
components={animatedComponents}
isMulti
onChange={handleChange}
onInputChange={handleInputChange}
cacheOptions
defaultOptions
defaultMenuIsOpen={false}
closeMenuOnSelect={true}
placeholder={placeholder}
options={tagOptions}
styles={customStyles}
formatOptionLabel={formatOptionLabel}
/>
)
}
export default TagsAutocomplete
I finally got it working!
Above, it had been working only on the initial page load (and the first input of a tag). Clicking into the autocomplete box a second time would result in No Options being shown.
Surprisingly, the part that took me a really long time to debug was that getTagCounts
had been returning an array of objects like { label: tag, count: tagCount, }
, and I needed to edit it to be { label: tag, value: tag, count: tagCount, }
. I don't know why it ever worked on each first load.
import React, { useState, useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import makeAnimated from 'react-select/animated'
import Select from 'react-select' //https://react-select.com/home
import { getTagCounts } from '../temp/api'
import { fetchFilteredPosts } from '../actions'
const animatedComponents = makeAnimated()
const BaseAutocomplete = ({ placeholder, classNamePrefix, filterKey }) => {
const dispatch = useDispatch()
const [tagOptions, setTagOptions] = useState([])
const [tagQuery, setTagQuery] = useState('')
const posts = useSelector((state) => state.db.posts)
useEffect(() => {
const tagCounts = getTagCounts(posts, tagQuery)
setTagOptions(tagCounts)
}, [posts])
const handleChange = (newValue, actionMeta) => {
console.group('Value Changed')
console.log(newValue)
console.log(`action: ${actionMeta.action}`)
const tags = newValue ? newValue.map((tagOption) => tagOption.label) : []
const newFilter = {}
newFilter[filterKey] = tags
dispatch(fetchFilteredPosts(newFilter))
setTagQuery('')
console.groupEnd()
}
const handleInputChange = (inputValue, actionMeta) => {
console.group('Input Changed')
console.log(inputValue)
setTagQuery(inputValue)
console.log(`action: ${actionMeta.action}`)
console.groupEnd()
}
const customStyles = {
//https://react-select.com/styles#style-object
option: (styles, { data, isDisabled, isFocused, isSelected }) => {
return {
...styles,
fontSize: '12px',
textAlign: 'left',
cursor: isDisabled ? 'not-allowed' : 'default',
':active': {
...styles[':active'],
},
}
},
}
const formatOptionLabel = (
{ value, label, count }
) => (
<>
<span className="tagLabel">{label}</span>
<span className="tagCount">({count})</span>
</>
)
return (
<Select
components={animatedComponents}
isMulti
onChange={handleChange}
onInputChange={handleInputChange}
cacheOptions
defaultOptions
defaultMenuIsOpen={false}
closeMenuOnSelect={true}
placeholder={placeholder}
options={tagOptions}
styles={customStyles}
formatOptionLabel={formatOptionLabel}
classNamePrefix={classNamePrefix}
/>
)
}
export default BaseAutocomplete
This @helmarjunior Worked for me thanks,
<Async
key={JSON.stringify(this.state.someUpdatedProp)}
...
/>
but there should be a proper way of managing this kind of stuff
Try making the cacheOptions={false}. This worked for me. This will not cache old option and give you new list
Is there any new news regarding forcing react-select to fetch?
Bump.
The key={JSON.stringify(some_changing_state_object)}
just solved an hours long battle for me.
I needed to show available defaultOptions
onMenuOpen as well as hide options if they'd already been added to some local state. filterOption
was working but was not filtering onMenuOpen until the input value changed -- which defeats the purpose of using the custom filter as it wasn't immediately hiding options that had already been pushed to the new array.
Pointing the key to the array i was pushing to forced the reload, and ran the filter correctly.
I've started a fork of react-select. Feel free to resubmit this issue on the fork and/or submit a PR to resolve this issue on the fork and we can get it merged and released.
EDIT: :tada: I've archived the fork now that we've got some momentum in this repo and Jed is involved again. Sorry for the disturbance!
Greetings everyone,
This appears to be a duplicate of https://github.com/JedWatson/react-select/issues/1879 so I will be closing this.
Please note that I agree that this is a mechanism that should be implemented from within the library and will be a talking point and hopefully new or improved feature within a future version of react-select.
Thank you everyone for your contributions.
Most helpful comment
This works for me:
Example working: https://github.com/helmarjunior/react-hooks-select-async