Reputation: 1106
I have a simple form with a select field, it's react-hook-form for validation and everything. There's a Controller
which renders a Material UI Select
. I would like to set the value of such select using setValue from outside the component (in the root of the form, where all controls reside).
This is the piece of code I'm using (slightly simplified not to waste too much of your time)
type Props = {
name: string;
control: Control<any>;
options: SelectOptions[];
};
const Select: FunctionComponent<Props> = ({
name,
control,
options,
}) => (
<Controller
control={control}
name={name}
render={({ field: { onChange, value } }) => {
return (
<FormControl>
<MuiSelect onChange={onChange}>
{options.map((o) => (
<MuiSelectItem key={o.key} value={o.value}>{o.label}</MuiSelectItem>
))}
</MuiSelect>
</FormControl>
)
}}
/>
);
As far as changing the value of the select, setValue
works magically. When I feed a new value, it works as intended. The problem (I guess) is the component is not re-rendered, so the old value is still shown. I'm not sure how to fix this thing and docs did not help a lot. Any help is much appreciated, thanks!
Upvotes: 18
Views: 45238
Reputation: 581
Here's a snippet from my codebase. In my case, I simply added a ternary operator to MUI's value prop. My previous code value={value}
became value={value ? value : ""}
and it sufficed to force MUI to rerender on each value
change. I'm not fully certain on why this works, but if anyone knows, I would love to be enlightened.
<Controller
control={props.control}
name={props.name}
render={({ field: { onChange, value } }) => {
return (
<TextField
size="small"
fullWidth
value={value ? value : ""}
type="text"
label={props.label}
{...props.register(props.name)}
onChange={(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
onChange(e);
if (props.onAfterChange) {
props.onAfterChange(e);
}
}}
/>
);
}}
/>
Hope this helps!
Upvotes: 1
Reputation: 3520
As @knoefel said I tried setting the defaultValue=""
but doesn't work for me(maybe because I am using FormProvider
). So what I did is use watch
instead of value
<Controller
name='name'
control={control}
render={({ field: { onChange } }) => (
<Select
dropdownValues={dropdownValues}
value={watch('name')}
onChange={onChange}
/>
)}
/>
Upvotes: 17
Reputation: 6949
I think you just forgot to set the value
prop of <Controller />
to your <MuiSelect />
. You also have to set a defaultValue
for your <Controller />
field, either via the defaultValue
prop or via useForm
.
<Controller
control={control}
name={name}
defaultValue=""
render={({ field: { onChange, value } }) => {
return (
<FormControl>
<MuiSelect onChange={onChange} value={value}>
{options.map((o) => (
<MuiSelectItem key={o.key} value={o.value}>{o.label}</MuiSelectItem>
))}
</MuiSelect>
</FormControl>
)
}}
/>
Upvotes: 6