Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m42s
136 lines
3.8 KiB
JavaScript
136 lines
3.8 KiB
JavaScript
import { useState, useCallback } from 'react';
|
|
|
|
/**
|
|
* useForm - hook для управления формами с валидацией
|
|
*
|
|
* @param {Object} initialValues - начальные значения полей
|
|
* @param {Object} validationSchema - схема валидации {fieldName: validatorFn}
|
|
* @returns {Object} - {values, errors, touched, isSubmitting, handlers}
|
|
*
|
|
* Пример использования:
|
|
* const { values, errors, handleChange, handleBlur, handleSubmit } = useForm(
|
|
* { email: '', password: '' },
|
|
* {
|
|
* email: (value) => !value ? 'Email обязателен' : null,
|
|
* password: (value) => value.length < 6 ? 'Минимум 6 символов' : null
|
|
* }
|
|
* );
|
|
*/
|
|
function useForm(initialValues, validationSchema = {}) {
|
|
const [values, setValues] = useState(initialValues);
|
|
const [errors, setErrors] = useState({});
|
|
const [touched, setTouched] = useState({});
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
|
|
// Валидация одного поля
|
|
const validateField = useCallback((name, value) => {
|
|
if (!validationSchema[name]) return null;
|
|
|
|
const validator = validationSchema[name];
|
|
const error = validator(value, values);
|
|
|
|
return error;
|
|
}, [validationSchema, values]);
|
|
|
|
// Обработчик изменения поля
|
|
const handleChange = useCallback((name, value) => {
|
|
setValues(prev => ({ ...prev, [name]: value }));
|
|
|
|
// Валидация при изменении, если поле уже было touched
|
|
if (touched[name]) {
|
|
const error = validateField(name, value);
|
|
setErrors(prev => ({ ...prev, [name]: error }));
|
|
}
|
|
}, [touched, validateField]);
|
|
|
|
// Обработчик blur (потеря фокуса)
|
|
const handleBlur = useCallback((name) => {
|
|
setTouched(prev => ({ ...prev, [name]: true }));
|
|
|
|
const value = values[name];
|
|
const error = validateField(name, value);
|
|
setErrors(prev => ({ ...prev, [name]: error }));
|
|
}, [values, validateField]);
|
|
|
|
// Валидация всех полей
|
|
const validate = useCallback(() => {
|
|
const newErrors = {};
|
|
let isValid = true;
|
|
|
|
Object.keys(validationSchema).forEach(name => {
|
|
const error = validateField(name, values[name]);
|
|
if (error) {
|
|
newErrors[name] = error;
|
|
isValid = false;
|
|
}
|
|
});
|
|
|
|
setErrors(newErrors);
|
|
return isValid;
|
|
}, [validationSchema, values, validateField]);
|
|
|
|
// Обработчик submit
|
|
const handleSubmit = useCallback(async (onSubmit) => {
|
|
setIsSubmitting(true);
|
|
|
|
// Отмечаем все поля как touched
|
|
const allTouched = Object.keys(values).reduce((acc, key) => {
|
|
acc[key] = true;
|
|
return acc;
|
|
}, {});
|
|
setTouched(allTouched);
|
|
|
|
const isValid = validate();
|
|
|
|
if (isValid) {
|
|
try {
|
|
await onSubmit(values);
|
|
} catch (error) {
|
|
console.error('Form submission error:', error);
|
|
throw error;
|
|
} finally {
|
|
setIsSubmitting(false);
|
|
}
|
|
} else {
|
|
setIsSubmitting(false);
|
|
}
|
|
}, [values, validate]);
|
|
|
|
// Сброс формы
|
|
const reset = useCallback(() => {
|
|
setValues(initialValues);
|
|
setErrors({});
|
|
setTouched({});
|
|
setIsSubmitting(false);
|
|
}, [initialValues]);
|
|
|
|
// Установка значения поля программно
|
|
const setValue = useCallback((name, value) => {
|
|
setValues(prev => ({ ...prev, [name]: value }));
|
|
}, []);
|
|
|
|
// Установка ошибки поля программно
|
|
const setError = useCallback((name, error) => {
|
|
setErrors(prev => ({ ...prev, [name]: error }));
|
|
}, []);
|
|
|
|
return {
|
|
values,
|
|
errors,
|
|
touched,
|
|
isSubmitting,
|
|
handleChange,
|
|
handleBlur,
|
|
handleSubmit,
|
|
validate,
|
|
reset,
|
|
setValue,
|
|
setError,
|
|
setValues,
|
|
setErrors
|
|
};
|
|
}
|
|
|
|
export default useForm;
|
|
|