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:
defaultValue
ordefaultValues
to provide the default values in the fieldtransformers
parameter 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]);