Reputation: 641
Previously I used to write like this:
<input className="form-control" name="productImage" type='file' onChange={handleImageUpload} ref={register({ required: true })} />
After the update I have to write like this:
<input className="form-control" type="file" {...register('productImage', { required: true })} />
How do I use onChange={handleImageUpload}
on the updated version of React Hook Form?
Here is the migration docs
Upvotes: 64
Views: 186877
Reputation: 377
Here is how you can use the onChange together with React hook form and Controller
<Controller
name="address"
control={control}
render={({ field }) => (
<TextField
{...field}
type="text"
label="address"
onChange={(e) => {
field.onChange(e);
yourCustomChangeHandler(e);
}}
/>
)}
/>
<Controller
Upvotes: 1
Reputation: 1960
When using a Controller
with a control
instance I created a handleOnChange
method that essentially extends the onChange
method passed by the Control.render
method.
Like so:
const SomeForm = () => {
const { control, getValues } = useForm({
defaultValues: { foo: 1, bar: 2 },
mode: "all",
reValidateMode: "onChange",
shouldUnregister: false,
});
const onChangeHandler = useCallback((onChange: (...event: any[]) => void) => {
return (...event: any[]) => {
onChange(...event);
const formAfterChange = getValues();
// do what you want after the change happens.
};
}, [getValues]);
return <>
<Controller
control={control}
name={"foo"}
render={({ value, onChange }) => (
<Input
value={value}
onChange={onChangeHandler(onChange)}
/>
)}
/>
<Controller
control={control}
name={"bar"}
render={({ value, onChange }) => (
<Input
value={value}
// if you do some logic before calling onChange
onChange={(e) => {
let nextValue;
if ((e.target.value ?? 0) >= 100) {
nextValue = e.target.value + 10;
} else {
nextValue = e.target.value;
}
onChangeHandler(onChange)(nextValue);
}}
/>
)}
/>
</>;
}
Upvotes: 0
Reputation: 2239
I am using form hook's watch method to capture changes instead of the input's onChange event.
https://react-hook-form.com/api/useform/watch
Upvotes: 1
Reputation: 2324
You can use react-hook-form control
<Controller
render={({ field }) => <input onChange={event=>{
handleImageUpload(event);
field.onChange(event);
}} />}
name="image"
control={control}
/>
Upvotes: 6
Reputation: 2796
You just have to move the onChange
props after {...register(...)}
const productImageField = register("productImage", { required: true });
return (
<input
className="form-control"
type="file"
{...productImageField}
onChange={(e) => {
productImageField.onChange(e);
handleImageUpload(e);
}}
/>
)
(Dec 3 2021) edit: this approach is no longer correct since react-hook-form v7.16.0's changes, see @Bill's answer.
Upvotes: 47
Reputation: 447
Was stuck with the same problem. For me the problem was that my onChange was above the react-hook-form's {...register} and moving it below the register solved the problem for me!!
Upvotes: 4
Reputation: 19338
https://github.com/react-hook-form/react-hook-form/releases/tag/v7.16.0
V7.16.0 has introduced this new API for custom onChange
.
<input
type="text"
{...register('test', {
onChange: (e) => {},
onBlur: (e) => {},
})}
/>
Upvotes: 133
Reputation: 71
In register
documentation https://react-hook-form.com/api/useform/register, sample exists on Custom onChange, onBlur
section :
// onChange got overwrite by register method
<input onChange={handleChange} {...register('test')} />
// register's onChange got overwrite by register method
<input {...register('test')} onChange={handleChange}/>
const firstName = register('firstName', { required: true })
<input
onChange={(e) => {
firstName.onChange(e); // method from hook form register
handleChange(e); // your method
}}
onBlur={firstName.onBlur}
ref={firstName.ref}
/>
So for your case :
const productImageRegister = register("productImage", {required: true})
<input className="form-control"
type="file"
{...productImageRegister }
onChange={e => {
productImageRegister.onChange(e);
handleImageUpload(e);
}} />
Upvotes: 7
Reputation: 423
For me, decoration solution worked
const fieldRegister = register("productImage", {required: true})
const origOnChange = fieldRegister.onChange
fieldRegister.onChange = (e) => {
const res = origOnChange(e)
const value = e.target.value
// do something with value
return res
}
For field declaration use
<input {...fieldRegister}/>
Upvotes: 1
Reputation: 119
I faced a similar issue recently when migrating to V7. If it can help anybody.
A parent component handling the form was passing down to a wrapper the register function, the wrapper passing it down again to an input that needed debouncing on change.
I called the register formLibraryRef
in case I wanted to use a different library later but overall I had to do something like:
const { onChange, ...rest } = formLibraryRef(inputName);
pass the onChange to the function that is itself passed to the native onChange event of the input:
const handleDebouncedChange: (event: React.ChangeEvent<HTMLInputElement>) => void = (
event: ChangeEvent<HTMLInputElement>,
) => {
onChange(event);
if (preCallback) {
preCallback();
}
debounceInput(event);
};
and then pass the rest to the input:
<input
aria-label={inputName}
name={inputName}
data-testid={dataTestId}
className={`form-control ...${classNames}`}
id={inputId}
onChange={handleDebouncedChange}
onFocus={onFocus}
placeholder={I18n.t(placeholder)}
{...rest}
/>
The register
section in the docs here: https://react-hook-form.com/migrate-v6-to-v7/ gives a bit more info on how to get the onChange and shows an example for Missing ref
.
Upvotes: 0