Zod Validation in [React + Typescript]
Zod
1. Type Definition (
2. State for Errors (
3.
4.
Zod is a TypeScript-first schema declaration and validation library. It allows you to define validation schemas for data structures, such as objects, strings, numbers, arrays, etc. Zod validates the data according to the schema and provides clear error messages if the data doesn't match the expected structure.
Basically it helps us to define a schema for a data structure and then validate that data structure values against the schema and give us proper error.
Key Features of Zod:
- Type-safe: Zod integrates seamlessly with TypeScript, ensuring that the types of data are validated correctly and that type inference works as expected.
- Declarative Validation: You define a schema that describes the expected structure of the data, and Zod will automatically validate the data against that schema.
- Error Handling: Zod provides detailed, easy-to-understand error messages when validation fails, making it simple to debug validation issues.
- Composability: You can combine Zod schemas to create more complex data structures, making it easy to reuse and compose validation logic.
- Asynchronous Validation: Zod supports asynchronous validation for scenarios such as checking if a value exists in a database.
Okay, Let's move to the coding part, best practice with zod validation library.
For me it is to create a custom hook and then use it everywhere according to my need, you can explore your best choice and let me know more in comments so I can learn new ways too.
Now move to the code, so here we are going to create a custom hook named useFormValidation which will return us an object containing three fields
- errors: This will contains an objects with key of form data and error associated with as value.
- validateField: It is a function which will validate a particular field of a form. It takes two params- first one is name of field which we want to validate and the other one is the value of that field.
- validateForm: It is also a function which will validate the whole form in one go. It takes only one param that is form data in the object form.
Okay now its time to create our custom hook as we explained above. First we are going to install zod in our react + typescript project using command
npm install zod
After installing the zod we will create a file name form-validation.tsx and put this code there
import { useState } from "react";
import { z, ZodSchema } from "zod";
type UseZodValidationProps<T> = {
schema: ZodSchema<T>;
};
export const useZodValidation = <T extends Record<string, any>>({
schema,
}: UseZodValidationProps<T>) => {
const [errors, setErrors] = useState<Record<string, string>>({});
// Validate a single field dynamically as the user types
const validateField = (fieldName: keyof T, value: any) => {
const result = schema.safeParse({ [fieldName]: value });
if (!result.success) {
const error = result.error.format()[fieldName]?._errors?.[0] || "";
setErrors((prevErrors) => ({ ...prevErrors, [fieldName]: error }));
} else {
setErrors((prevErrors) => {
const { [fieldName]: _, ...rest } = prevErrors;
return rest;
});
}
};
// Validate the entire form using the provided form data
const validateForm = (data: T) => {
const result = schema.safeParse(data);
if (!result.success) {
const formattedErrors = result.error.format();
const errors = Object.keys(data).reduce((acc, key) => {
if (formattedErrors[key]) {
acc[key] = formattedErrors[key]._errors[0];
}
return acc;
}, {} as Record<string, string>);
setErrors(errors);
return false;
}
setErrors({});
return true;
};
return { errors, validateField, validateForm };
};
Let's explain each part
Code Explanation
1. Type Definition (UseZodValidationProps
)
- This type defines the shape of the props that the
useZodValidation
hook will receive. The hook expects aschema
prop, which is aZodSchema
(a validation schema from theZod
library). TheT
represents a generic type for form data (the schema type).
2. State for Errors (useState
)
errors
is a state variable that will store validation errors for each field. It's an object where each key is a field name, and the value is the corresponding error message.setErrors
is used to update this state.
3. validateField
Function
validateField
is called when you want to validate a single field dynamically (e.g., on each input change).- Parameters:
fieldName
: The name of the field to validate (e.g.,"email"
).value
: The current value of the field (e.g., the input value).
- Inside the function:
safeParse({ [fieldName]: value })
: This usesZod
'ssafeParse
method to validate the specific field (fieldName
) against the schema. The schema is designed to validate the entire object, so we pass a partial object with just the field we're validating.- If validation fails (
!result.success
), we extract the error message from the result and update theerrors
state with the field's error message. - If the field is valid, we remove any previous error for that field from the
errors
state.
4. validateForm
Function
validateForm
is used to validate the entire form (all fields) at once.- Parameters:
data
: The form data (an object) that needs to be validated against theschema
.
- Inside the function:
safeParse(data)
: This validates the entire form data.- If validation fails, it formats the error and creates an
errors
object containing error messages for each invalid field. ThesetErrors
function is then called to update the state with these errors. - If validation passes, it clears any previous errors by setting
setErrors({})
and returnstrue
to indicate success.
5. Return Object
- The hook returns the following:
errors
: The current errors object containing validation error messages for the form fields.validateField
: A function to validate a single field in real-time (for example, when the user types in a field).validateForm
: A function to validate the entire form (for example, when submitting the form).
How This Works in a Component
- You can use this hook in your form components to manage field validation.
validateField
is used for validating individual fields in real-time (e.g., when a user types in a field).validateForm
is used when submitting the form, to ensure that all fields are validated at once.
Let's see an example to use this hook in a form
Example Usage in a Component
Comments
Post a Comment