Type casting and default values
Type casting with the transformers parameter
When you retrieve the values from for fields, by default you always get a string (and a boolean for the checked property of a checkbox).
But sometimes it can be handy to cast the string value to something that can be more appropriate for you case, and in that case you can use the transformers parameter:
import type { FormEvent } from 'react';
import type { IProps } from '../types';
import { type IFormValues, useForm } from '@per-form/react';
const transformers = { count: Number };
export default function Demo(props: IProps) {
function handleSubmit(_e: FormEvent<HTMLFormElement>, values: IFormValues) {
console.log(values);
}
const { errors, formProps } = useForm({
...props,
onSubmit: handleSubmit,
transformers,
});
return (
<form {...formProps}>
<input name="count" required type="number" />
{errors.all.count && <div className="error">{errors.all.count}</div>}
<div className="actions">
<button type="submit">Submit</button>
<button type="reset">Reset</button>
</div>
</form>
);
}
The transformer function ges the value to cast as parameter and should return the casted value.
There is no quotes around the logged value when you submit the form.
Default values
With the defaultValue props
If you want to have default value for your form you can simply use the defaultValue props on the input (defaultChecked for checkbox and radio buttons):
import type { FormEvent } 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 } = useForm({
...props,
onSubmit: handleSubmit,
});
return (
<form {...formProps}>
<input defaultValue="0" name="count" required type="number" />
{errors.all.count && <div className="error">{errors.all.count}</div>}
<div className="actions">
<button type="submit">Submit</button>
<button type="reset">Reset</button>
</div>
</form>
);
}
With the defaultValues parameter
Or you can use the defaultValues parameter:
import type { FormEvent } from 'react';
import type { IProps } from '../types';
import { type IFormValues, useForm } from '@per-form/react';
const defaultValues = { count: 0 };
export default function Demo(props: IProps) {
function handleSubmit(_e: FormEvent<HTMLFormElement>, values: IFormValues) {
console.log(values);
}
const { errors, formProps } = useForm({
...props,
defaultValues,
onSubmit: handleSubmit,
});
return (
<form {...formProps}>
<input name="count" required type="number" />
{errors.all.count && <div className="error">{errors.all.count}</div>}
<div className="actions">
<button type="submit">Submit</button>
<button type="reset">Reset</button>
</div>
</form>
);
}
Declare the default values outside the component to avoid creating a new reference for each new render.
If you don't @per-form/react will update the form values with the default ones on the next render.
If you can't declare them outside, then use useMemo.
Even if we give defaultValues a number, the logged value is a string.
Indeed, defaultValues is only responsible for initializing the values in the fields.
If you want to convert the value, use the transformers parameter like in the example below.
With type casting
If you want to use type casting and have default values, simply combine both:
defaultValueordefaultValuesto provide the default values in the fieldtransformersparameter to cast the value
import type { FormEvent } from 'react';
import type { IProps } from '../types';
import { type IFormValues, useForm } from '@per-form/react';
const defaultValues = { count: 0 };
const transformers = { count: Number };
export default function Demo(props: IProps) {
function handleSubmit(_e: FormEvent<HTMLFormElement>, values: IFormValues) {
console.log(values);
}
const { errors, formProps } = useForm({
...props,
defaultValues,
onSubmit: handleSubmit,
transformers,
});
return (
<form {...formProps}>
<input name="count" type="number" />
{errors.all.count && <div className="error">{errors.all.count}</div>}
<div className="actions">
<button type="submit">Submit</button>
<button type="reset">Reset</button>
</div>
</form>
);
}
Loading default values asynchronously
In this example imagine that the useData hook loads some data over the network and then returns the value asynchronously (for the example we simply update the state after 1 second with "Asynchronous value").
import type { IProps } from '../types';
import { type FormEvent } from 'react';
import { type IFormValues, useForm } from '@per-form/react';
import { useData } from '../useData';
export default function Demo(props: IProps) {
const data = useData();
function handleSubmit(_e: FormEvent<HTMLFormElement>, values: IFormValues) {
console.log(values);
}
const { errors, formProps } = useForm({
...props,
onSubmit: handleSubmit,
});
return (
<form {...formProps}>
<input defaultValue={data} name="text" required />
{errors.all.text && <div className="error">{errors.all.text}</div>}
<div className="actions">
<button type="submit">Submit</button>
<button type="reset">Reset</button>
</div>
</form>
);
}
Change the form options (useNativeValidation, mode or revalidateMode) to reinitialize the form and see the update again.
We can also use the defaultValues parameters but in that case it is necessary to use useMemo:
const defaultValues = useMemo(() => ({ text: data }), [data]);