Summary
The issue at hand is combining zodResolver with field-level validation in React Hook Form (RHF), where the validation depends on data fetched from a hook. The problem arises when using zodResolver with a schema, as it seems to override the rules.validate function, preventing the field-level validation from running.
Root Cause
The root cause of this issue is the way zodResolver integrates with React Hook Form. When using zodResolver, it takes precedence over the rules.validate function, causing the field-level validation to be ignored. The main causes are:
- zodResolver overriding rules.validate
- React Hook Form architecture
- Zod schema validation taking precedence over field-level validation
Why This Happens in Real Systems
This issue occurs in real systems due to the following reasons:
- Complex validation requirements: Fields may require validation based on dynamic data fetched from hooks or APIs.
- Modular code structure: Schemas are often created at a higher level in the component tree, making it difficult to access and modify them in individual field components.
- Reusability of components: Components are designed to be reusable, but this can lead to limitations in terms of validation flexibility.
Real-World Impact
The impact of this issue is significant, as it can lead to:
- Inconsistent validation: Field-level validation may not be applied consistently, resulting in incorrect or missing validation errors.
- Poor user experience: Users may not receive accurate feedback on validation errors, leading to frustration and confusion.
- Security vulnerabilities: Inadequate validation can expose applications to security risks, such as data injection attacks.
Example or Code
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
entityName: z.string(),
});
const SomeFormComponent = () => {
const { control, setValue } = useForm({
resolver: zodResolver(schema),
});
const { dataFromServer } = useServerSelectOptions();
return (
{
// Custom validation logic based on hook data
if (value === dataFromServer?.serverValue) {
return 'Name already exists';
}
},
}}
render={({ field, fieldState }) => (
)}
/>
);
};
How Senior Engineers Fix It
Senior engineers can fix this issue by using a combination of zodResolver and custom validation techniques, such as:
- SuperRefine: Using superRefine to refine the schema based on dynamic data.
- Refine + Context: Using refine with a custom context to access hook data.
- Custom Resolver: Creating a custom resolver to handle field-level validation.
- setError: Using setError to manually set validation errors.
Why Juniors Miss It
Junior engineers may miss this issue due to:
- Lack of experience: Limited experience with React Hook Form and Zod.
- Insufficient understanding: Not fully understanding the integration between zodResolver and React Hook Form.
- Overlooking documentation: Failing to read and understand the documentation for zodResolver and React Hook Form.