Запрет ввода в input в зависимости от value в react-hook-form
Я настроил так useForm:
const {
register,
watch,
handleSubmit,
setValue,
setError,
formState: { errors }
} = useForm<UserSubmitForm>({
defaultValues: {
firstName: "",
secondName: ""
},
mode: "onChange"
});
Так у меня отрисовываются input`ы:
return (
<form className="modal__form" onSubmit={handleSubmit(onSubmit)}>
<div className="modal__body">
<div className="modal__info">
<TextAreaWithLimit
register={register}
watch={watch}
errors={errors}
setValue={setValue}
setError={setError}
name={"firstName"}
placeholder={"Заголовок"}
limit={50}
/>
<TextAreaWithLimit
register={register}
watch={watch}
errors={errors}
setValue={setValue}
setError={setError}
name={"secondName"}
placeholder={"Второй заголовок"}
limit={9}
/>
</div>
<input type="submit" />
<div className="modal__img">
<img src={cardImg} alt="" />
</div>
</div>
</form>
);
В компонент с инпутом, как видно передается значение лимита. В самом компоненте мне надо добиться следующих проверок. Require - это я сделал.
const TextAreaWithLimit = ({ register, watch, errors, name, placeholder, limit }: TextAreaWithLimitProps) => {
const valueField = watch(name);
return (
<div className="modal__formItem">
<textarea
{...register(name, {
required: { value: true, message: "Обязательное поле" },
})}
readOnly={valueField.length==limit}
rows={1}
className="modal__textArea"
placeholder={placeholder}
/>
<span className="modal__textArea-limit">{errors[name] ? errors[name]?.message : (limit - valueField.length)}</span>
</div>
);
};
Далее, мне необходимо валидировать форму по максимальному кол-ву символов. При этом мне надо останавливать ввод, если valueField === limit и возобновлять его, когда это условие не выполняется. Я пробовал использовать и onChange и disable. Но не могу добиться корректного выполнения скрипта. Помогите, я новичок в react hook form
Ответы (1 шт):
Создаем и выводим ошибки ввода данных с помощью react-hook-form
Опишем правила, по которым мы хотим выдавать ошибки пользователю
{...register(name, {
required: { value: true, message: "Обязательное поле" },
maxLength: { value: limit, message: `Максимум ${limit} знаков` },
minLength: { value: 1, message: `Минимум 1 знак` }
})}
Теперь компонент будет контролировать минимальную и максимальную длину данных в поле ввода.
Внутри компонента мы можем отслеживать изменение состояния ввода и выполнять любые действия. Допустим, сгенерируем кастомную ошибку, при помощи setError, о превышении некоторого количества символов(это просто пример)
useEffect(() => {
if (valueField.length > 3 && valueField.length < 7) {
setError(`${name}Err`, {
type: "custom",
message: `${name} Пользовательская ошибка для демонстрации`
});
} else {
clear();
}
}, [valueField]);
Для сброса ошибок, необходимо воспользоваться методом clearErrors компонента react-hook-form
Там где нам надо отобразить эту ошибку, добавляем вывод. Имена должны быть одинаковыми!
{errors[`${name}Err`] ? (
<span>
{errors[`${name}Err`]?.message}
</span>
) : null}
Или мы можем сделать так, что бы ненужных ошибок не появлялось впринципе и всегда обрезать введенные данные пользователем до необходимой длины или выполнять любые другие преобразования по желанию
useEffect(() => {
if (valueField.length > limit) {
setValue(name, valueField.substring(0, limit));
}
}, [valueField]);
Полный код компонента на основе вашего примера
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import "./styles.css";
const TextAreaWithLimit = ({
register,
watch,
errors,
name,
placeholder,
limit,
setError,
clear,
setValue
}) => {
const valueField = watch(name);
useEffect(() => {
if (valueField.length > 3 && valueField.length < 7) {
setError(`${name}Err`, {
type: "custom",
message: `${name} Пользовательская ошибка для демонстрации`
});
} else {
clear();
}
if (valueField.length > limit ) {
setValue(name, valueField.substring(0, limit));
}
}, [valueField]);
return (
<div className="modal__formItem">
<textarea
{...register(name, {
required: { value: true, message: "Обязательное поле" },
maxLength: { value: limit, message: `Максимум ${limit} знаков` },
minLength: { value: 1, message: `Минимум 1 знак` }
})}
rows={1}
className="modal__textArea"
placeholder={placeholder}
/>
<br />
<span className="modal__textArea-limit">
{errors[name] ? errors[name]?.message : limit - valueField.length}
{errors[`${name}Err`] ? (
<span>
<br />
{errors[`${name}Err`]?.message}
</span>
) : null}
</span>
</div>
);
};
export default function App() {
const {
register,
watch,
handleSubmit,
setValue,
setError,
clearErrors,
formState: { errors }
} = useForm({
defaultValues: {
firstName: "",
secondName: ""
},
mode: "onChange"
});
return (
<div className="App">
<form className="modal__form" onSubmit={handleSubmit(onSubmit)}>
<div className="modal__body">
<div className="modal__info">
<TextAreaWithLimit
register={register}
watch={watch}
errors={errors}
setValue={setValue}
setError={setError}
name={"firstName"}
placeholder={"Заголовок"}
limit={50}
clear={clearErrors}
/>
<TextAreaWithLimit
register={register}
watch={watch}
errors={errors}
setValue={setValue}
setError={setError}
name={"secondName"}
placeholder={"Второй заголовок"}
limit={9}
clear={clearErrors}
/>
</div>
<input type="submit" />
<div className="modal__img">
<img src={cardImg} alt="" />
</div>
</div>
</form>
</div>
);
}