Skip to main content

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:

0
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.

note

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):

0
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:

0
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>
);
}
warning

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.

note

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:

  1. defaultValue or defaultValues to provide the default values in the field
  2. transformers parameter to cast the value
0
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").

0
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>
);
}
tip

Change the form options (useNativeValidation, mode or revalidateMode) to reinitialize the form and see the update again.

note

We can also use the defaultValues parameters but in that case it is necessary to use useMemo:

const defaultValues = useMemo(() => ({ text: data }), [data]);