-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to set value of AsyncSelect outside of the component? #3761
Comments
Using
|
Hi @Xartok The problem is not when user is changing it (after the select has focus and user is typing something) as this is working. The problem is when I set Value prop externally (first time, when, for instance, I set Value prop from database). This won't trigger onInputChange anymore and, in not doing so, it won't load the array options. |
So actually, when you set the value from your database, what is displayed:
|
In the menu: nothing (as it expects a pair {value/label} in the Value prop. |
Ok, so do you store the label along with the value in the database ? If this is the case you can set the value of the AsyncSelect to the object {label: dbLabel, value: dbValue} (without doing loadOptions('').then(options => options.find(opt => opt.value === dbValue)) as this is supported (it will filter out the option with this value in the menu) and avoid an unnecessarily call to loadOptions. But it requires a modification of your database query... |
Yes, this is what I've done. But I have to (as you said) change my query (outside of the component) and manually craft a label/value object. The problem with this approach is that I had to duplicate this query (one query to search for the label before creating the component) and the other inside the component to loadOptions. |
Same here. I have only the value/id (not the entire object, like: { value: '1': label: 'First' }). So I set defaultValue like this: { value: form.fieldId } but I don't have the label (It will be searched by loadOptions). So I need to load my option before render AsyncSelect and pass value or defaultValue prop |
Greetings, Is this still an issue as it sounds like there is a solution? This type of behavior would require a controlled input and updating the value once the defaultOptions load. Here is a working demo: codesandbox As a note, if you would like to trigger the onChange event, there is a selectOption available in the select ref which I believe triggers the onChange methods. const AsyncExample = ({ defaultOptionValue, ...props }) => {
const [value, setValue] = useState();
const [defaultValue, setDefaultValue] = useState();
useEffect(() => {
setValue(defaultValue);
}, [defaultValue]);
const loadOptions = (searchKey) => {
return new Promise((resolve) => {
setTimeout(() => {
!defaultValue &&
setDefaultValue(options.find((o) => o.value === defaultOptionValue));
const filtered = options.filter((o) => o.label.includes(searchKey));
resolve(filtered);
}, 5000);
});
};
const onChange = (option) => setValue(option);
return (
<Async
loadOptions={loadOptions}
defaultOptions
value={value}
onChange={onChange}
/>
);
}; |
In an effort to cleanup stale issues, I will be closing this. Please feel free to reply or create a new issue if there are any concerns or reproducible bugs. |
I am doing a similar thing as @MarcosCunhaLima described, I am prefilling the data from the database (which cannot have all those exactly the same data as |
Greetings @flora8984461 , This would require a controlled input so that a fetch can be made to get the default value. const AsyncLookup = props => {
const { defaultId, ...selectProps } =props;
const [ value, setValue ] = useState();
const [ isLoading, setIsLoading ] = useState(false);
const onChange = opt => {
setValue(opt);
props.onChange && props.onChange(opt);
}
useEffect(() => {
if (!defaultId) return;
setIsLoading(true);
fetch('your.api.com').then(resp => {
const defaultValue = resp.results.find(x => x.id === defaultId);
defaultValue && setValue(defaultValue);
}).finally(() => setIsLoading(false));
}, [ defaultId ]);
return <AsyncSelect {...selectProps} onChange={onChange} value={value} isLoading={isLoading} />
} Let me know if this makes sense or needs a bit of explanation whats going on |
This is what works for me: import AsyncSelect from 'react-select/async';
import { client } from 'api/dato';
import debounce from 'debounce-async';
import { useMemo, useState } from 'react';
const isOptionSelected = (option, values) => {
return values.some(({ value }) => option.value === value);
};
export default function AccountInput({ field, form }) {
const [lastOptions, setLastOptions] = useState([]);
const loadOptions = useMemo(() => {
return debounce(async (inputValue) => {
const { data } = await client
.url('/accounts')
.query({ q: inputValue, id: field.value })
.get()
.json();
const options = data.map((account) => ({
value: account.id,
label: `${account.attributes.email} (#${account.id})`,
}));
setLastOptions(options);
return options;
}, 300);
}, [field.value, setLastOptions]);
return (
<div>
<AsyncSelect
cacheOptions
loadOptions={loadOptions}
defaultOptions
isOptionSelected={isOptionSelected}
value={lastOptions.find((option) => option.value === field.value)}
onChange={(option) => {
form.setFieldValue(field.name, option.value);
}}
/>
</div>
);
} |
Thanks @stefanoverna, this part helped me: value={lastOptions.find((option) => option.value === field.value)} |
I have read all the documentation of AsyncSelect and Select but I didn't read anything regarding this matter.
The problem arose after upgrading from V1 to V3. In V1, I could set value property (a simple value or string) and this would trigger the async loading procedure which would get the right value object (label and value).
But, in V3, you should set value with the whole structure, eg, {label: xxx, value: yyy} in order to show it correctly.
For instance, we have this sample:
All the logic of loading colors is inside the component. In order to set a value from outside, I would have to (in an external procedure) load the array and search for the value which, I think, would duplicate code unnecessarily.
Is there a way to set a value and this would trigger internal loading procedure in order to search for the correct pair?
The text was updated successfully, but these errors were encountered: