I’ve read a few similar questions around class based approaches to this question, and am yet to find one that loads the contents of the autocomplete from the network at the same time as trying to set an originally agreed default value.
My question is, how do I correctly provide a picker control that can load its options from the network and at the same time optionally supply a default value without MUI or react complaining that the autocomplete doesn’t give this error: “A component is changing the default value state of an uncontrolled Autocomplete after being initialized. To suppress this warning opt to use a controlled Autocomplete.”
We shall use my ‘Currency’ picker control (functional component) as an example. Note also that I’m a beginner to react so all additional pointers appreciated:
{
value: string | undefined
onValueChanged: (value: string | undefined) => void
}
export const CurrencyPicker = ({ value, onValueChanged = () => {}, required = false, fullWidth = true }: Props) => {
const { loading, error, data } = useQuery<CurrenciesReponse>(GET_CURRENCIES, { fetchPolicy: 'cache-and-network'});
const [ selectedValue, setSelectedValue ] = useState<Currency|null>( {id: "31c7613c-6b6b-4956-9ab6-74089bed4b1a", name:"GBP", iso:"GBP", symbol:"£" });
useEffect(() => {
const selected = data?.currencies.find(c => c.id === value);
if ( selected )
{
setSelectedValue(selected);
}
}, [data?.currencies, value]);
return <Autocomplete options={data?.currencies ?? []}
getOptionLabel={(option : Currency) => option.symbol + " (" + option.iso + ")"}
onChange={(e, v) => {
onValueChanged(v?.id);
}}
defaultValue={selectedValue}
loading={loading}
fullWidth={fullWidth}
filterSelectedOptions
renderInput={(params) => (
<TextField
{...params}
type="text"
variant="outlined"
placeholder="Currency"
fullWidth={fullWidth}
required={required}
/>)}/>
}
The above code ‘kinda’ works. But it seems that if I drop the initial state (i.e. the {id: “31c7613c-6b6b-4956-9ab6-74089bed4b1a”, name:”GBP”, iso:”GBP”, symbol:”£” }) bit in the selectedValue initial state then the control goes into a different mode and complains about having a defaultValue set in an async fashion – this is obviously very ugly and a value I shouldn’t really know as a UI. Just an FYI that the useQuery is from the Apollo GraphQL library but that shouldn’t matter I’d think. Mainly the problem is that as the control is rendered, the known options are not immediately known, but the options themselves are selected by reference rather than id. In the case of the ‘value’ that is a GUID in general terms.
I’ve read that you can use isOptionEqualToValue={(o, v) => o.id === v.id} for example but that seems to make little difference to the complaints from the console. So can anyone suggest a better way of achieving this outcome? Is there a way of setting say the ‘key’ that I want on the autocomplete and then waiting for the network to supply values? Or do I need to push the network values into a state and do some useEffect magic?