Пользовательский хук React для проверки работает неправильно

Я работаю с формой в реакции, поэтому я создал собственный хук для обработки формы и проверки, который работает нормально, но недавно я обнаружил в этом некоторую проблему, которая не подходит для более чем одной формы, предположим, что одна форма - это форма входа, а затем, когда я вхожу в систему, у меня также есть несколько других форм, которые не работают в этом сценарии.

Что я сделал

  • Компонент «Мое поле ввода»

    <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 17.04.2023 12:41

В ваших разделах о проблемах говорится, что вы делаете, а не в чем проблема?

Aleksandar 17.04.2023 12:42

@Aleksandar Я уже упоминал, что когда я нажимаю на форму 2, не получаю значения, потому что она также проверяет проверку формы 1.

user15744841 17.04.2023 14:23

@AleksandarАлександр, я еще раз объяснил в своем редактировании, пожалуйста, проверьте.

user15744841 18.04.2023 07:52

Не могли бы вы добавить пошаговую инструкцию, как воспроизвести вашу ошибку? Не уверен, что происходит не так. Кстати; оба ваших сообщения делают console.info("form2", values);, вы должны изменить первую форму на журнал form1. Кроме того, вы делаете console.info(errors); в Form1, а не в Form2, имейте это в виду;)

0stone0 19.04.2023 20:56

@0stone0 Я думаю, если вы посмотрите на консоль, ошибка будет приходить для всех полей вместе. ОП хочет разделения. Если вы поместите журналы в оба, вы также увидите ошибку для формы 1 в форме 2 и формы 2 в форме 1.

Tushar Shahi 19.04.2023 21:26

Если у вас две формы, вам нужно вызвать хук дважды, назвать каждую переменную по-разному, т.е. Добавьте 1 или 2 и передайте правильные переменные в каждую форму. Ты сделал это? В противном случае формы будут иметь одно и то же состояние. Т.е. Один вызов ловушки на форму.

Chris Hamilton 23.04.2023 14:00

@chrisHamilton, не могли бы вы поделиться одним примером

user15744841 23.04.2023 19:22

@Марка, ты смотрел песочницу, которую я разместил? Чего не хватает в этом

Tushar Shahi 24.04.2023 07:06
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
9
175
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Так что это определенно можно решить, используя 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
  };
};

Есть два изменения:

  1. Добавлен новый параметр, который содержит все ссылки на входы для проверки.
  2. 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, я знаю вы скажете использовать эту библиотеку, но я хочу знать об этом все больше и больше

user15744841 20.04.2023 07:30

Если вы не хотите иметь onChange на входе, вы также не должны передавать ему значение. Это делает его полностью неуправляемым. Это можно сделать, как я сделал по этой ссылке codeandbox.io/s/runtime-leaf-mff5ru?file=/src/…. Дайте мне знать, если это поможет, и я обновлю ответ

Tushar Shahi 20.04.2023 08:35

Вы не показали полный пример, но похоже, что вы делите одно и то же состояние между двумя формами.

Хуки создают новые переменные состояния каждый раз, когда они вызываются. Итак, если вам нужны две формы с отдельным состоянием, вам нужно дважды вызвать хук:

  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, поэтому не знаю, нужны ли вам две его копии.

Если что-то непонятно, то покажите полный пример с обеими формами.

Другие вопросы по теме