react-hook-form's setValue method is not working if input is in material ui dialog
The problem is with the register function. You are registering the Textfield with register after the ref of the Textfield is called.
The useEffect is called to set the name to 123 with setValue
after the initial render. If open
is true, the dialog content is rendered after the useEffect.
After the content is rendered, the ref with register is called and the default value of Textfield (here undefined
) is set to be the value of name.
That is why the value of the Textfield is "" on show. You need to call setValue after the render and ref callback is called, so that the value persists.
You have two options to do that:
- Set the value async in the useEffect with an async delay (
setTimeout
or promise) afteropen
changed. So if you addopen
to the useEffect dependecy array and set the value async, it works. Here is a Sandbox. - Set the default value of either the Textfield or add the default value to the hook with
useForm({defaultValues: {name: '123}})
.
For external controlled component
If you are using V3, i would recommend to use react-hook-form-input
https://github.com/react-hook-form/react-hook-form-input
import React from 'react';
import useForm from 'react-hook-form';
import { RHFInput } from 'react-hook-form-input';
import Select from 'react-select';
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
];
function App() {
const { handleSubmit, register, setValue, reset } = useForm();
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<RHFInput
as={<Select options={options} />}
rules={{ required: true }}
name="reactSelect"
register={register}
setValue={setValue}
/>
<button type="button">Reset Form</button>
<button>submit</button>
</form>
);
}
If you are using V4, i would recommend to use Controller
https://react-hook-form.com/api/#Controller
import React from 'react';
import Select from 'react-select';
import { TextField } from "@material-ui/core";
import { useForm, Controller } from 'react-hook-form';
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
];
function App() {
const { handleSubmit, control } = useForm();
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<Controller
as={<Select options={options} />}
control={control}
rules={{ required: true }}
onChange={([selected]) => {
// React Select return object instead of value for selection
return { value: selected };
}}
name="reactSelect"
/>
<Controller
as={<TextField />}
name="firstName"
control={control}
/>
<button>submit</button>
</form>
);
}
The idea to wrap your controlled component and collecting data within while still isolate re-render inside the external controlled component.