如何使用反应以多步形式进行验证

Posted

技术标签:

【中文标题】如何使用反应以多步形式进行验证【英文标题】: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 已经是了,但是他们已经使用了路由,我没有为这个东西使用路由,我永远不应该使用它。 【参考方案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)

【讨论】:

嘿,正在使用您的代码,但卡在了一个地方我提出了一个新问题,请您检查一下***.com/questions/64241134/hot-validate-react-form【参考方案2】:

主要问题是您有条件地呈现表单,因此所有以前的表单值都被删除。解决方案是保持所有表单都已安装,并根据选择的表单使用display: nonedisplay: 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;

【讨论】:

以上是关于如何使用反应以多步形式进行验证的主要内容,如果未能解决你的问题,请参考以下文章

如何在 NextJS 中以多步形式传递数据?

如何在反应中验证多步表单

反应采取错误验证的多步骤形式

如何实现一个简单的反应多步控制

如何在角度 2 中以反应形式重置验证器?

使用反应钩子形式进行条件验证