Skip to main content

Watch

You can use the watch methods to kind of replace controlled component (or do anything you want with the values you get).

Compared to controlled component, using watch, you won't need to reset the state using the onReset parameter for example (check the controlled component example).

warning

Watch is only getting the value when the user changes it.

It is not a two way data binding like with controlled components.

With the useWatch hook

You can use the useWatch hook to declare a state that will contains the values of the watched fields.

The useWatch take only one optional parameter to define the list of field names you want to watch (you can provide a string, an array of string or nothing to watch all values).

0
value =
import { type FormEvent } from 'react';
import type { IProps } from '../types';
import {
FormProvider,
type IFormValues,
useForm,
useFormErrors,
useWatch,
} from '@per-form/react';

function Input() {
const errors = useFormErrors();
const { text } = useWatch<{ text: string }>('text');
return (
<>
<input name="text" required />
{errors.all.text && <div className="error">{errors.all.text}</div>}
<div>value = {text}</div>
</>
);
}

export default function Demo(props: IProps) {
function handleSubmit(_e: FormEvent<HTMLFormElement>, values: IFormValues) {
console.log(values);
}

const { formProps, ...context } = useForm({
...props,
onSubmit: handleSubmit,
});

return (
<FormProvider {...context}>
<form {...formProps}>
<Input />
<div className="actions">
<button type="submit">Submit</button>
<button type="reset">Reset</button>
</div>
</form>
</FormProvider>
);
}
info

Changing the field value does not trigger the render counter in the top left corner because the render only happens in the <Input> child component.

warning

With the hook version you will have to add yourself the @per-form/react <FormProvider> component !

With the watch function

You can get the watch function from the useForm hook or with the context.

The watch accept two parameters:

  1. The watch callback, fired when the values change.
  2. The list of field names you want tp watch (you can provide a string, an array of string or nothing to watch all values).
0
value =
import { type FormEvent, useEffect, useState } from 'react';
import type { IProps } from '../types';
import { type IFormValues, useForm } from '@per-form/react';

export default function Demo(props: IProps) {
function handleSubmit(_e: FormEvent<HTMLFormElement>, values: IFormValues) {
console.log(values);
}

const { errors, formProps, watch } = useForm({
...props,
onSubmit: handleSubmit,
});

const [text, setText] = useState('');
useEffect(() => {
return watch<{ text: string }>(({ text }) => setText(text), 'text');
}, [watch]);

return (
<form {...formProps}>
<input name="text" required />
{errors.all.text && <div className="error">{errors.all.text}</div>}
<div>value = {text}</div>
<div className="actions">
<button type="submit">Submit</button>
<button type="reset">Reset</button>
</div>
</form>
);
}
note

In that case you have to define the state yourself (if you want to).

info

The watch function return a function for unsubscribing the watch. You can directly return that function in your useEffect.