【问题标题】:How to give validation in multi step form using react如何使用反应以多步形式进行验证
【发布时间】:2020-11-02 06:56:49
【问题描述】:

我正在处理一个我已经完成的多步骤表单以及验证部分的场景。我正在使用react-hook-form 进行验证。

我有多步表格:

  • 在第一种形式中,我有几个字段和一个单选按钮
  • 默认情况下,auto generated pass 的单选按钮处于选中状态,所以在这种情况下,我无事可做
  • 第二个是let me create a password,所以在这种情况下,将显示一个输入字段,用户将创建密码

问题

在我的最终表单中,我正在进行如下验证:

{
  fields: ["uname", "email", "password"], //to support multiple fields form
  component: (register, errors, defaultValues) => (
    <Form1
      register={register}
      errors={errors}
      defaultValues={defaultValues}
    />
  )
},

所以为了验证 uname、email 和密码,我将传递上述值。

但是当勾选自动生成密码的单选按钮时,它仍在处理验证,我点击下一步,由于密码字段,它不会进入下一步。

如果我将单选按钮选中为let me create the password,它会转到下一个表单,当我点击back 返回时,它会再次转到auto generated password,它不会保持以前的状态。对于其他输入字段,它正在处理以前的值,但在单选按钮情况下不处理。

My full working code sandbox

【问题讨论】:

  • 你看过这个视频吗:youtube.com/watch?v=CeAkxVwsyMU
  • @Bill 已经是了,但是他们已经使用了路由,我没有为这个东西使用路由,我永远不应该使用它。

标签: javascript reactjs react-hooks react-hook-form


【解决方案1】:

答案1 原因是你fields: ["uname", "email", "password"] 是固定的,password 总是要被验证的。 解决方案 需要将Form1 的状态保存在App 中,以便检查auto generated password 的状态是否为从列表中删除密码

App.js

... other code
// need to move state and function form Form to app
const [show_input, setshow_input] = useState(false);

  const createInput = () => {
    setshow_input(true);
  };
  const auto_text = () => {
    setshow_input(false);
  };
  const forms = [
    {
      // validate based on show_input state
      fields: show_input ? ["uname", "email", "password"] : ["uname", "email"], //to support multiple fields form
      component: (register, errors, defaultValues) => (
        <Form1
          register={register}
          errors={errors}
          defaultValues={defaultValues}
          auto_text={auto_text}
          createInput={createInput}
          show_input={show_input}
        />
      )
    },
    {
      fields: ["lname"],
      component: (register, errors, defaultValues) => (
        <Form2
          register={register}
          errors={errors}
          defaultValues={defaultValues}
        />
      )
    },
    {
      component: (register, errors, defaultValues) => (
        <Form3
          register={register}
          errors={errors}
          defaultValues={defaultValues}
        />
      )
    }
  ];
... other code

答案 2 当你下一步时,Form1 被卸载,因此它的状态被破坏。当您将 Form1 的状态存储在 App.js 中时,您也将解决此问题

奖励:最好使用 camalCase(例如:showInput)而不是下划线(show_input)

【讨论】:

【解决方案2】:

主要问题是您有条件地呈现表单,因此所有以前的表单值都被删除。解决方案是保持所有表单都已安装,并根据选择的表单使用display: none 或display: block。这样,每当您转到下一个或上一个表单或提交表单时,所有值都将保持不变。

第二个问题是您在卸载时没有删除密码字段,因此当调用 moveToNext 时,triggerValidation 回调中的 valid 参数始终为 false。我通过根据密码输入是否可见有条件地设置 Form1 的字段来解决此问题。

您将defaultValues 用于错误目的的第三个问题。您可以使用getValues() 获取当前表单值,这将返回表单的所有当前值。

我将uname字段的默认值设置为一个示例,向您展示如何使用defaultValues。

您可以在此处查看完整的解决方案:https://codesandbox.io/s/fragrant-forest-75pzs?file=/src/App.js

这里是所有更改的文件:

App.js

import React, { useState } from "react";
import Form1 from "./components/Form1";
import Form2 from "./components/Form2";
import Form3 from "./components/Form3";
import { useForm } from "react-hook-form";

function MainComponent() {
  const {
    register,
    triggerValidation,
    defaultValues,
    errors,
    getValues
  } = useForm({
    // You can set default values here
    defaultValues: {
      uname: "Lol"
    }
  });
  console.log("Errors: ", errors);
  const [currentForm, setCurrentForm] = useState(0);

  // control password input visibility and Form1 fields
  const [passwordVisible, setPasswordVisible] = useState(false);

  const showPassword = () => {
    setPasswordVisible(true);
  };
  const hidePassword = () => {
    setPasswordVisible(false);
  };

  const forms = [
    {
      fields: passwordVisible
        ? ["uname", "email", "password"]
        : ["uname", "email"],
      component: (register, errors) => (
        <Form1
          // a key is needed to render a list
          key={0}
          // this will be used to set the css display property to block or none on each form
          shouldDisplay={currentForm === 0}
          register={register}
          errors={errors}
          showPassword={showPassword}
          hidePassword={hidePassword}
          passwordVisible={passwordVisible}
        />
      )
    },
    {
      fields: ["lname"],
      component: (register, errors) => (
        <Form2
          key={1}
          shouldDisplay={currentForm === 1}
          register={register}
          errors={errors}
        />
      )
    },
    {
      component: (register, errors) => (
        <Form3
          key={2}
          shouldDisplay={currentForm === 2}
          register={register}
          errors={errors}
          values={getValues()}
        />
      )
    }
  ];

  const moveToPrevious = () => {
    triggerValidation(forms[currentForm].fields).then(valid => {
      if (valid) setCurrentForm(currentForm - 1);
    });
  };

  const moveToNext = () => {
    triggerValidation(forms[currentForm].fields).then(valid => {
      if (valid) setCurrentForm(currentForm + 1);
    });
  };

  const prevButton = currentForm !== 0;
  const nextButton = currentForm !== forms.length - 1;
  const handleSubmit = e => {
    console.log("whole form data - ", getValues());
  };
  return (
    <div>
      <div className="progress">
        <div>{currentForm}</div>
      </div>

      {forms.map(form => form.component(register, errors))}

      {prevButton && (
        <button
          className="btn btn-primary"
          type="button"
          onClick={moveToPrevious}
        >
          back
        </button>
      )}
      {nextButton && (
        <button className="btn btn-primary" type="button" onClick={moveToNext}>
          next
        </button>
      )}

      {currentForm === 2 && (
        <button
          onClick={handleSubmit}
          className="btn btn-primary"
          type="submit"
        >
          Submit
        </button>
      )}
    </div>
  );
}

export default MainComponent;

表格1

import React from "react";

function Form1({
  register,
  errors,
  shouldDisplay,
  passwordVisible,
  showPassword,
  hidePassword
}) {
  return (
    <div style={{ display: shouldDisplay ? "block" : "none" }}>
      <form autoComplete="on">
        <br />
        <div className="form-group">
          <label>User name</label>
          <input type="text" name="uname" ref={register({ required: true })} />
          {errors.uname && <span>required</span>}
          <label>Email</label>
          <input type="email" name="email" ref={register({ required: true })} />
          {errors.email && <span>required</span>}
        </div>
        <div>
          <div className="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
            <label className="form_label">Password</label>
            <div className="form-check">
              <label>
                <input
                  type="radio"
                  name="auto_pass"
                  id="Radios1"
                  value="auto_pass"
                  className="form-check-input"
                  defaultChecked={true}
                  onChange={hidePassword}
                />
                Auto generated password
              </label>
            </div>
            <div className="form-check">
              <label>
                <input
                  type="radio"
                  name="auto_pass"
                  id="Radios2"
                  value="let_me"
                  className="form-check-input"
                  onChange={showPassword}
                />
                Let me create the password
              </label>
            </div>
          </div>
          {passwordVisible && (
            <div className="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 mb-3">
              <label className="form_label">Password</label>
              <input
                type="password"
                name="password"
                className="form-control"
                ref={register({ required: true })}
              />
              {errors.password && (
                <span className="text-danger">Password is reguired</span>
              )}
            </div>
          )}
        </div>
      </form>
    </div>
  );
}

export default Form1;

Form2

import React from "react";

function Form2({ register, errors, shouldDisplay }) {
  return (
    <div style={{ display: shouldDisplay ? "block" : "none" }}>
      <form autoComplete="on">
        <br />
        <div className="form-group">
          <label>User last name</label>
          <input type="text" name="lname" ref={register({ required: true })} />
          {errors.lname && <span>required</span>}
        </div>
      </form>
    </div>
  );
}

export default Form2;

Form3

import React from "react";

function Form3({ values, shouldDisplay }) {
  return (
    <div style={{ display: shouldDisplay ? "block" : "none" }}>
      <h3>Want to display all values here like below</h3>
      {Object.entries(values).map(([key, value]) => (
        <p key={key}>
          {key}: {value}
        </p>
      ))}

      <br />
      <p>So that use can check for any Wrong info</p>
    </div>
  );
}

export default Form3;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-23
    • 2022-10-16
    • 1970-01-01
    • 2022-08-02
    • 2020-10-08
    • 1970-01-01
    • 1970-01-01
    • 2023-02-03
    相关资源
    最近更新 更多