I am using MUI with React Hooks and TypeScript. I have a reusable component, Dropdown in my application which uses the Autocomplete component:
export interface DropdownInterface {
id: string,
value?: string | string[] | null,
defaultValue?: string | string[] | null,
options: string[],
onChange: (e: any, newValue: any) => void,
renderInput: (params: AutocompleteRenderInputParams) => React.ReactNode,
isMultiSelect?: boolean,
}
const Dropdown = ( { id, value, defaultValue, options, onChange, renderInput, isMultiSelect,
}: DropdownInterface): JSX.Element => {
const [open, setOpen] = useState(false);
return (
<Autocomplete
id={id}
value={value}
defaultValue={defaultValue}
options={options}
multiple={isMultiSelect}
onChange={onChange}
renderInput={renderInput}
isOptionEqualToValue={(option, currentValue) => option === currentValue}
filterSelectedOptions
fullWidth
open={open}
onOpen={() => setOpen(true)}
onClose={() => setOpen(false)}
/>
);
};
Note the presence of both value for controlled instances and defaultValue for uncontrolled.
I am able to use this component successfully as a controlled component for both single-select and multi-select (hence the isMultiSelect prop above) in a generic form dialog. I am attempting to refactor my form dialog to uncontrolled components. I have done so by wrapping sections of my form dialog in an HTML form tag:
<form noValidate onSubmit={(event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
console.log(formData.entries());
const fieldValues = Object.fromEntries(formData.entries());
console.log(fieldValues);
handleSubmit(fieldValues);
}}>
<DialogContent>
{content}
</DialogContent>
<DialogActions>
<Button onClick={closeDialog}>
{actionLabels.cancel}
</Button>
<Button type="submit">
{actionLabels.submit}
</Button>
</DialogActions>
</form>
Autocomplete as uncontrolled returns a string for single-select, and so my custom component worked as expected, with Object.fromEntries(formData.entries()) returning a fieldValue as expected. This instance of my custom component, however, did not:
<Dropdown
id="roles"
isMultiSelect={true}
defaultValue={user ? user.roles.map(r => r.name) : []}
options={roles.map(r => r.name)}
renderInput={(params) => (
<TextField
{...params}
name="roles"
label="Roles"
margin="dense"
/>
)}
/>
When I submitted the form, I received roles: '' in the object returned by Object.fromEntries(formData.entries()). From the docs, when multiple is true on Autocomplete, value will be an array. How does multiple affect defaultValue, and can multiple be true on uncontrolled instances of Autocomplete?