Я работаю с формой в реакции, поэтому я создал собственный хук для обработки формы и проверки, который работает нормально, но недавно я обнаружил в этом некоторую проблему, которая не подходит для более чем одной формы, предположим, что одна форма - это форма входа, а затем, когда я вхожу в систему, у меня также есть несколько других форм, которые не работают в этом сценарии.
Что я сделал
Компонент «Мое поле ввода»
<form onSubmit = {handleSubmit}>
<input
type = "text"
className = {`${errors.fName && "input-error"}`}
name = "fName"
id = "fName"
onChange = {handleChangeEvent}
value = {values.fName || ""}
/>;
</form>
Я написал один пользовательский хук useForm для обработки изменений, отправки и проверки, ниже приведен код
import { useState, useEffect } from "react";
const useForm = (callback, validate) => {
const [values, setValues] = useState({});
const [errors, setErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
useEffect(() => {
if (Object.keys(errors).length === 0 && isSubmitting) {
callback();
}
}, [errors]);
const handleSubmit = (event) => {
if (event) event.preventDefault();
setErrors(validate(values));
setIsSubmitting(true);
};
const handleChangeEvent = (event) => {
event.persist();
setValues((values) => ({
...values,
[event.target.name]: event.target.value,
}));
};
return {
handleChangeEvent,
handleSubmit,
values,
errors,
};
};
export default useForm;
Теперь ниже мой файл validation.js
export default function validate(values) {
let errors = {};
if (!values.emailAddress) {
errors.emailAddress = "Email address is required";
}
if (!values.password) {
errors.password = "Password is required";
}
if (!values.fName) {
errors.fName = "first name is required";
}
if (!values.lName) {
errors.lName = "last name is required";
}
return errors;
}
Теперь в моем основном компоненте, где поля ввода являются декларатором, я вызываю хук формы использования и передаю функцию щелчка и проверки, и функция щелчка будет работать только после функции проверки. Ниже показано, как я делаю
const { values, errors, handleChangeEvent, handleSubmit } = useForm(
btnClick,
Validate
);
Действия по воссозданию проблемы
email address
, password
, firstname
, lastname
.email address
и password
в одной форме, а firstname
и lastname
в другой форме.values
, потому что для этой формы все еще существуют две ошибки.Что я ищу
Если я могу сделать это с помощью useRef/ref, как это делает https://react-hook-form.com/
, где нет onchange, и если я не хочу валидировать какой-либо ввод, я просто не буду проходить ref
Мне нравится ответ @TusharShahi, и я буду следовать ему, но я ищу больше вариантов, которые являются более общим кодом.
В ваших разделах о проблемах говорится, что вы делаете, а не в чем проблема?
@Aleksandar Я уже упоминал, что когда я нажимаю на форму 2, не получаю значения, потому что она также проверяет проверку формы 1.
@AleksandarАлександр, я еще раз объяснил в своем редактировании, пожалуйста, проверьте.
Не могли бы вы добавить пошаговую инструкцию, как воспроизвести вашу ошибку? Не уверен, что происходит не так. Кстати; оба ваших сообщения делают console.info("form2", values);
, вы должны изменить первую форму на журнал form1
. Кроме того, вы делаете console.info(errors);
в Form1, а не в Form2, имейте это в виду;)
@0stone0 Я думаю, если вы посмотрите на консоль, ошибка будет приходить для всех полей вместе. ОП хочет разделения. Если вы поместите журналы в оба, вы также увидите ошибку для формы 1 в форме 2 и формы 2 в форме 1.
Если у вас две формы, вам нужно вызвать хук дважды, назвать каждую переменную по-разному, т.е. Добавьте 1 или 2 и передайте правильные переменные в каждую форму. Ты сделал это? В противном случае формы будут иметь одно и то же состояние. Т.е. Один вызов ловушки на форму.
@chrisHamilton, не могли бы вы поделиться одним примером
@Марка, ты смотрел песочницу, которую я разместил? Чего не хватает в этом
Так что это определенно можно решить, используя refs и немного изменив функцию проверки.
Хотя это можно сделать с помощью одной функции проверки, помните, что необходимо передать функции значения полей, которые она должна проверять. Без этого он не знал бы, какие значения проверять, и проверял бы все значения.
Вот как я бы изменил функцию проверки:
const errMap = {
emailAddress: "Email address is required",
password: "Password is required",
fName: "first name is required",
lName: "last name is required"
};
function validate(values, namesToCheck) {
let errors = {};
for (let i = 0; i < namesToCheck.length; i++) {
if (!values[namesToCheck[i]]) {
errors[namesToCheck[i]] = errMap[namesToCheck[i]];
}
}
return errors;
}
errMap
— это просто простой объект конфигурации, чтобы указать, как будет выглядеть ошибка каждого значения поля. Ключ — это имя поля, а значение — это сообщение об ошибке.
Поскольку наше решение должно быть достаточно расширяемым для ситуации, когда не все поля в одной форме нуждаются в проверке, хук также должен измениться. Он должен разрешать передачу только тех полей, которые необходимо проверить.
const useForm = (callback, validate, inputsToCheck) => {
const [values, setValues] = useState({});
const [errors, setErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
useEffect(() => {
if (Object.keys(errors).length === 0 && isSubmitting) {
callback();
}
}, [errors]);
const handleSubmit = (event) => {
if (event) event.preventDefault();
let namesToCheck = inputsToCheck.map(({ current: { name } = {} }) => name);
setErrors(validate(values, namesToCheck));
setIsSubmitting(true);
};
const handleChangeEvent = (event) => {
event.persist();
setValues((values) => ({
...values,
[event.target.name]: event.target.value
}));
};
return {
handleChangeEvent,
handleSubmit,
values,
errors
};
};
Есть два изменения:
handleSubmit
изменен для извлечения имен, которые необходимо передать validate
.Наконец, передача правильных ссылок на хук завершит решение.
const Form2 = () => {
const btn2Click = () => {
console.info("form2", values);
};
const fnameRef = useRef();
const lnameRef = useRef();
const { values, errors, handleChangeEvent, handleSubmit } = useForm(
btn2Click,
validate,
[fnameRef, lnameRef]
);
return (
<div>
<form onSubmit = {handleSubmit}>
<div className = "row">
<div className = "input-group">
<label>First name</label>
<input
ref = {fnameRef}
type = "text"
className = {`${errors.fName && "input-error"}`}
name = "fName"
id = "fName"
onChange = {handleChangeEvent}
value = {values.fName || ""}
/>
<p className = "error-text">{errors.fName}</p>
</div>
<div className = "input-group">
<label>last name</label>
<input
ref = {lnameRef}
type = "text"
className = {`${errors.lName && "input-error"}`}
name = "lName"
id = "lName"
onChange = {handleChangeEvent}
value = {values.lName || ""}
/>
<p className = "error-text">{errors.lName}</p>
</div>
</div>
<button type = "submit" className = "btn">
Click 2
</button>
</form>
</div>
);
};
PS: Я не вижу никакой проблемы в создании двух функций проверки. Оба могут находиться в одном и том же файле. И тогда вы можете передать правильный при вызове вашего хука. С отдельными функциями проверки вам не нужно передавать список входных данных, которые необходимо проверить, поскольку ваша индивидуальная функция проверки будет обслуживаться вашими полями формы. Я также хотел бы предложить, чтобы ваши индивидуальные методы проверки находились рядом с вашими формами. Form1 с Validate1 (при необходимости в отдельном файле).
Хорошо, я получил ваш ответ, и это нормально, и то, как я делаю, тоже хорошо. Я могу создавать различные функции проверки, но можем ли мы использовать useRef
без onchange, например, как это делает react-hook-form.com, я знаю вы скажете использовать эту библиотеку, но я хочу знать об этом все больше и больше
Если вы не хотите иметь onChange на входе, вы также не должны передавать ему значение. Это делает его полностью неуправляемым. Это можно сделать, как я сделал по этой ссылке codeandbox.io/s/runtime-leaf-mff5ru?file=/src/…. Дайте мне знать, если это поможет, и я обновлю ответ
Вы не показали полный пример, но похоже, что вы делите одно и то же состояние между двумя формами.
Хуки создают новые переменные состояния каждый раз, когда они вызываются. Итак, если вам нужны две формы с отдельным состоянием, вам нужно дважды вызвать хук:
const {
values: values1,
errors: errors1,
handleChangeEvent: handleChangeEvent1,
handleSubmit: handleSubmit1,
} = useForm(btnClick, validate);
const {
values: values2,
errors: errors2,
handleChangeEvent: handleChangeEvent2,
handleSubmit: handleSubmit2,
} = useForm(btnClick, validate);
Затем вы можете дать каждой форме соответствующие свойства.
Примечание: я не знаю, что такое btnClick
, поэтому не знаю, нужны ли вам две его копии.
Если что-то непонятно, то покажите полный пример с обеими формами.
В чем тут вообще проблема? Что работает не так"