Как выполнить валидацию для поля выбора (select) с помощью Zod?

У меня возникла проблема с валидацией кастомного компонента select. Я удачно применяю валидацию к стандартному input, зарегистрировав его, и все работает без дополнительных переменных для хранения значения. Однако, ситуация с кастомным селектом, который я реализовал на div, отличается — валидация не срабатывает. Я пробовал сделать select невидимым и присваивать ему значение, но это тоже не дало результатов. Есть ли способ реализовать валидацию для кастомного селекта без использования onChange?
  • 21 ноября 2024 г. 17:03
Ответы на вопрос 1
Да, вы можете использовать библиотеку Zod для валидации кастомного селектора (select), но это потребует от вас некоторого манипулирования с формой и использованием Zod. Я покажу вам, как это можно сделать.

Если вы используете, например, `react-hook-form` вместе с `Zod`, в прямом смысле вам нужно будет выполнить настройку валидации для вашего кастомного селектора.

### Пример

1. **Создайте кастомный селект**: Вы можете создать собственный компонент, который будет внутри себя хранить состояние выбранного значения.

```jsx
import React from 'react';

const CustomSelect = ({ options, value, onChange }) => {
    return (
        <div>
            <div onClick={() => onChange(value)}>
                {value || 'Select an option'}
            </div>
            <div>
                {options.map(option => (
                    <div key={option.value} onClick={() => onChange(option.value)}>
                        {option.label}
                    </div>
                ))}
            </div>
        </div>
    );
};

export default CustomSelect;
```

2. **Используйте `react-hook-form` и `Zod`**: Зарегистрируйте ваш кастомный селект как поле формы.

```jsx
import React from 'react';
import { useForm } from 'react-hook-form';
import { z, ZodSchema } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import CustomSelect from './CustomSelect';

// Определите вашу схему с помощью Zod
const schema = z.object({
    selectedOption: z.enum(['option1', 'option2', 'option3'], {
        errorMap: () => ({ message: 'Выберите вариант' }),
    })
});

const MyForm = () => {
    const {
        register,
        handleSubmit,
        setValue,
        formState: { errors }
    } = useForm({
        resolver: zodResolver(schema)
    });

    const onSubmit = (data) => {
        console.log(data);
    };

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <CustomSelect
                options={[
                    { value: 'option1', label: 'Option 1' },
                    { value: 'option2', label: 'Option 2' },
                    { value: 'option3', label: 'Option 3' },
                ]}
                // Устанавливаем значение в hook-form при выборе
                value={undefined} // Здесь вы можете хранить текущее значение,
                onChange={(value) => {
                    setValue('selectedOption', value); // Здесь вы устанавливаете значение
                }}
            />
            {errors.selectedOption && <span>{errors.selectedOption.message}</span>}
            <button type="submit">Submit</button>
        </form>
    );
};

export default MyForm;
```

### Объяснение кода:

1. **Кастомный компонент `CustomSelect`**:
   - Он принимает `options`, `value` и `onChange` как свойства.
   - При выборе опции вызывается переданный `onChange`, который обновляет значение в `react-hook-form`.

2. **Схема валидации**:
   - Мы используем Zod для определения схемы валидации, где `selectedOption` является обязательным.

3. **Форма**:
   - Используется `useForm` для управления состоянием формы.
   - При выборе нового значения в кастомном селекте, используется `setValue`, чтобы обновить значение поля `selectedOption`.

Такой подход позволяет избежать необходимости использования `onChange` на самих input или select, но тем не менее вы контролируете значение через обработчик событий, что позволяет выполнять валидацию корректно.
Похожие вопросы