Jeer
@Jeer
уверенный пользователь

Как вынести определение формы в другой файл react react-hook-form?

Привет,
Я разбираюсь в теме реакта useForm из react-hook-form. Получилось по туториалу написать login форму, с двумя полями login и password. Но я бы хотел вынести определение полей формы и обработчика в другой файл, и это у меня не получается. Ошибка, что нельзя использовать хуки вне тела компонента. Подскажите, пожалуйста, как можно это сделать?
Вот такой код у меня получился, класс LoginForm будет лежать в отдельном файле:

import { useContext } from "react";
import { useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";
import { UserContext, ApiContext } from "../../shared/contexts/global.context";
import UserModel from "../../shared/models/user.model";

class LoginForm {
  public login: any; // по хорошему перенести сюда всю логику определения поля с валидацией
  public password: any; // по хорошему перенести сюда всю логику определения поля с валидацией
  public handleSubmit: any;

  constructor() {
    this.init();
  }

  init = () => {
    const {
      register,
      handleSubmit,
    } = useForm();
    this.login = register("login");
    this.password = register("password", { required: true, minLength: 2 });
    this.handleSubmit = handleSubmit(this.#onSubmit);
  };

  #onSubmit = async (data: any) => {
    const api = useContext(ApiContext).authApi; // ERROR
    const userService = useContext(UserContext);
    let navigate = useNavigate();

    try {
      const usr = await api.login(data);
      console.log(usr);
      userService.User = new UserModel(usr);
      navigate("/");
    } catch (Exception) {
      alert("не подходит");
    }
  };
}

function LoginComponent() {
  const loginForm = new LoginForm();

  return (
    <div className="col-md-offset-3 col-md-6">
      <form className="form-horizontal" onSubmit={loginForm.handleSubmit}>
        <h4>Use a local account to log in.</h4>
        <hr />

        <div className="form-group row">
          <label className="col-md-2 control-label" htmlFor="login">
            Login, Email or Phone
          </label>
          {
            <div className="col-md-10">
              <input className="form-control" {...loginForm.login} />
            </div>
          }
        </div>

        <div className="form-group row">
          <label className="col-md-2 control-label" htmlFor="password">
            Password
          </label>
          {
            <div className="col-md-10">
              <input className="form-control" {...loginForm.password} />
            </div>
          }
        </div>

        <div className="form-group row">
          <div className="col-md-offset-2 col-md-10">
            <button className="btn btn-primary">Log in</button>
          </div>
        </div>
      </form>
    </div>
  );
}

export default LoginComponent;
  • Вопрос задан
  • 146 просмотров
Решения вопроса 1
@Serg32
Всё правильно, хуки можно использовать непосредственно внутри функциональных компонентов. В данном примере хук вызывается не в самом компоненте, а внутри метода init. Чтобы исправить, можно в самом компоненте вызывать хук useForm и дальше в качестве аргументов конструктора передавать register и handleSubmit.
class LoginForm {
  public login: any; // по хорошему перенести сюда всю логику определения поля с валидацией
  public password: any; // по хорошему перенести сюда всю логику определения поля с валидацией
  public handleSubmit: any;

  constructor(form) {
    this.init(form);
  }

  init = (form) => {
    this.login = form.register("login");
    this.password = form.register("password", { required: true, minLength: 2 });
    this.handleSubmit = form.handleSubmit(this.#onSubmit);
  };

  #onSubmit = async (data: any) => {
    const api = useContext(ApiContext).authApi; // ERROR
    const userService = useContext(UserContext);
    let navigate = useNavigate();

    try {
      const usr = await api.login(data);
      console.log(usr);
      userService.User = new UserModel(usr);
      navigate("/");
    } catch (Exception) {
      alert("не подходит");
    }
  };
}

function LoginComponent() {
  const form = useForm();
  const loginForm = new LoginForm(form);

  return (
    <div className="col-md-offset-3 col-md-6">
      <form className="form-horizontal" onSubmit={loginForm.handleSubmit}>
        <h4>Use a local account to log in.</h4>
        <hr />

        <div className="form-group row">
          <label className="col-md-2 control-label" htmlFor="login">
            Login, Email or Phone
          </label>
          {
            <div className="col-md-10">
              <input className="form-control" {...loginForm.login} />
            </div>
          }
        </div>

        <div className="form-group row">
          <label className="col-md-2 control-label" htmlFor="password">
            Password
          </label>
          {
            <div className="col-md-10">
              <input className="form-control" {...loginForm.password} />
            </div>
          }
        </div>

        <div className="form-group row">
          <div className="col-md-offset-2 col-md-10">
            <button className="btn btn-primary">Log in</button>
          </div>
        </div>
      </form>
    </div>
  );
}

export default LoginComponent;
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы