Add a function to validate form fields using Yup and custom async functions
See original GitHub issueIs your feature request related to a problem? Please describe. Today it is not possible to to mix async validations with Yup validations. We can only pass an Yup object that will check the whole form or create our own functions if we want to validate the fields individually.
Describe the solution you’d like It would be great to have a generic function where we could pass the key of the field we want to validate with its value, the schema for that specific field and other optional parameters if the user need to pass them for the function.
Describe alternatives you’ve considered I made some tests for a project that I’m working and solved this problem creating a function to first solve the Yup validation and then the custom validations if they exist:
const validate = async (value, key, schema, params) => {
return await schema.yupValidations[key]
.validate(value)
.then(value => {
if (schema.customValidations[key])
return schema.customValidations[key](value, params);
})
.catch(err => err.message);
};
export default validate;
For each form of the system I create a FormSchema file like the one below, where instead of having one Yup object for the whole form, I create one object for each field.
import * as Yup from "yup";
import api from "../services/api";
const SignupFormSchema = {
email: Yup.string()
.required("Email is required")
.email("Invalid format"),
name: Yup.string()
.required("Name is required")
.min(5, "Min length is 5"),
};
async function NameValidation(value) {
try {
const result = await api.get("https://swapi.co/api/people/1/?format=json");
if (value !== result.data.name) return "Invalid name";
} catch (err) {
return "Could not validate name. Network error";
}
}
export default {
yupValidations: SignupFormSchema,
customValidations: {
name: NameValidation,
}
};
When I register the component I pass the schemaValidate
inputRef={register({
validate: value => schemaValidate(value, field, schema, params)
})}
And the form could be written like this:
import React from "react";
import useForm from "react-hook-form";
import schema from "../../schemas/SignupFormSchema";
import TextInput from "../../components/TextInput";
import Button from "../../components/Button";
export default function SignupForm() {
const { register, errors, handleSubmit, clearError } = useForm({
mode: "onBlur"
});
const props = {
register,
errors,
clearError,
schema
};
const onSubmit = (data, e) => {
e.preventDefault();
console.log(data);
};
return (
<form>
<TextInput props={props} field="email" label="Email" />
<TextInput props={props} field="name" label="Name" />
<Button
handleSubmit={handleSubmit(onSubmit)}
label="submit"
color="primary"
/>
</form>
);
}
Additional context You can check the example where I tested this solution with TextFields, Selects and DatePickers from Material-UI here: https://github.com/giovanniantonaccio/react-hook-form-test,
Issue Analytics
- State:
- Created 4 years ago
- Reactions:14
- Comments:6 (3 by maintainers)
@giovanniantonaccio If I understood your issue correctly then I think it was facing similar problem, the think which I did to solve it was as follow
components/form/validationSchemaContext.js
components/form/index.js
components/input/index.js
Example usage
This way I have one validation schema but all inputs are validated separately. Changing value in one field does not trigger call to API to validate another field when its value was not changed.
It’s still not perfect as still blur event and submitting of form causes unnecessary validation. I think there is a need for some kind of memoization in validate function.
oh ok thanks, @giovanniantonaccio. Let’s leave this for a while to see if someone else facing a similar problem and then we can go from there. 👍