【问题标题】:Submit forms data in react在反应中提交表单数据
【发布时间】:2020-08-22 07:22:08
【问题描述】:

我有组件,其中每个我都有一个表单,点击下一个我打开一个新表单(调用新组件),当它是最后一个时,我将其更改为提交。

我想要达到的目标

1:在每次下一步和返回单击时,我都想使用 react-form-hook 验证我的表单

2:点击提交后,我应该可以看到所有数据

3:点击后面的数据不应该从输入中丢失

问题

所以对于验证,我使用react-hook-form,因为它使用起来非常简单,但是在这里我无法找到,因为我的按钮不在主要组件中的表单内,所以我将如何验证和提交提交时的表单点击所有数据。

我的代码

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

function AddCompanyMain() {
  const [currState, setCurrState] = useState(1);
  const [allState, setAllstate] = useState(3);

  const moveToPrevious = () => {
    setCurrState(currState - 1);
  };
  const moveToNext = () => {
    setCurrState(currState + 1);
  };

  return (
    <div>
      <div class="progress">
        <div>{currState}</div>
      </div>

      {currState === 1 && <Form1 />}
      {currState === 2 && <Form2 />}
      {currState === 3 && <Form3 />}

      {currState !== 1 && (
        <button
          className="btn btn-primary"
          type="button"
          onClick={moveToPrevious}
        >
          back
        </button>
      )}
      {currState !== allState && (
        <button className="btn btn-primary" type="button" onClick={moveToNext}>
          next
        </button>
      )}

      {currState === 3 && (
        <button className="btn btn-primary" type="submit">
          Submit
        </button>
      )}
    </div>
  );
}

export default AddCompanyMain;

我的完整代码Code sandbox

我只是在寻找一个好的方法,因为这里我不能将提交放在每个组件中,因为我必须在顶部显示步骤。

【问题讨论】:

    标签: javascript reactjs react-hook-form


    【解决方案1】:

    您可以lift the value state of each component up to the parent,然后将 onChange 属性传递给每个子项以更新每个子项的状态。我不确定这将如何与 react-hooks-form 一起使用,但这通常是您希望同步子组件状态的方式。

    import React from "react";
    import "./styles.css";
    
    const FormOne = ({ value, onChange }) => (
      <div>
        Form 1
        <input type='text' value={value} onChange={e => onChange(e.target.value)} />
      </div>
    
    )
    
    const FormTwo = ({ value, onChange }) => (
      <div>
        Form 2
        <input type='text' value={value} onChange={e => onChange(e.target.value)} />
      </div>
    )
    
    const FormThree = ({ value, onChange }) => (
      <div>
        Form 3
        <input type='text' value={value} onChange={e => onChange(e.target.value)} />
      </div>
    )
    
    export default function App() {
      const [formOne, setFormOne] = React.useState('')
      const [formTwo, setFormTwo] = React.useState('')
      const [formThree, setFormThree] = React.useState('')
      const [index, setIndex] = React.useState(0)
    
      const moveUp = (e) => {
        e.preventDefault()
    
        if (index !== 2) {
          setIndex(index => index += 1)
        }
      }
    
      const moveDown = (e) => {
        e.preventDefault()
    
        if (index !== 0) {
          setIndex(index => index -= 1)
        }
      }
    
      const handleSubmit = (e) => {
        e.preventDefault()
    
        console.log(formOne, formTwo, formThree)
      }
    
      const form = index === 0
        ? <FormOne value={formOne} onChange={setFormOne} />
        : index === 1
        ? <FormTwo value={formTwo} onChange={setFormTwo} />
        : <FormThree value={formThree} onChange={setFormThree} />
    
      return (
        <div className="App">
          <form onSubmit={handleSubmit}>
            {form}
            {index !== 0 && <button onClick={moveDown}>Back</button>}
            {index !== 2
              ? <button onClick={moveUp}>Next</button>
              : <button type='submit'>Submit</button>
            }
          </form>
        </div>
      );
    }
    

    【讨论】:

    • 检查编辑。这里有很多优化,但这应该让你开始。
    【解决方案2】:

    您可以通过以下方式解决您的问题:

    • 在 app.js 中,将表单存储在对象数组中并根据步骤(currentFrom 状态)呈现它们。
    • 在父组件(不在子 Form 组件中)调用 useForm,并将 register, errors, defaultValues 值作为 props 传递给您的 Form 组件。
    • 在您的Form 组件中,您需要获取register, etc 作为道具
    • defaultValues 保持在一个状态并在下一个/上一个的onClick 中更新它们。你需要getValues然后使用setValues设置状态(defaultValues)

    还有:

    • 为了在下一个/上一个按钮点击时触发验证,您需要使用triggerValidation

    • 为了在点击下一个/上一个时保留值,需要使用defaultValuesprop

    working demo is here

    代码片段

    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 AddCompanyMain() {
      const {
        register,
        triggerValidation,
        errors,
        setValue,
        getValues
      } = useForm();
      const [defaultValues, setDefaultValues] = useState({});
    
      const forms = [
        {
          fields: ["uname"],
          component: (register, errors, defaultValues) => (
            <Form1
              register={register}
              errors={errors}
              defaultValues={defaultValues}
            />
          )
        },
        {
          fields: ["lname"],
          component: (register, errors, defaultValues) => (
            <Form2
              register={register}
              errors={errors}
              defaultValues={defaultValues}
            />
          )
        },
        {
          fields: ["company"],
          component: (register, errors, defaultValues) => (
            <Form3
              register={register}
              errors={errors}
              defaultValues={defaultValues}
            />
          )
        }
      ];
    
      const [currentForm, setCurrentForm] = useState(0);
    
      const moveToPrevious = () => {
        setDefaultValues(prev => ({ ...prev, [currentForm]: getValues() }));
    
        triggerValidation(forms[currentForm].fields).then(valid => {
          if (valid) setCurrentForm(currentForm - 1);
        });
      };
    
      const moveToNext = () => {
        console.log(getValues());
        setDefaultValues(prev => ({ ...prev, [currentForm]: getValues() }));
        triggerValidation(forms[currentForm].fields).then(valid => {
          if (valid) setCurrentForm(currentForm + 1);
        });
      };
    
      const prevButton = currentForm !== 0;
      const nextButton = currentForm !== forms.length - 1;
    
      return (
        <div>
          <div class="progress">
            <div>{currentForm}</div>
          </div>
    
          {forms[currentForm].component(
            register,
            errors,
            defaultValues[currentForm]
          )}
    
          {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 === 3 && (
            <button className="btn btn-primary" type="submit">
              Submit
            </button>
          )}
        </div>
      );
    }
    
    export default AddCompanyMain;
    
    

    注意——一般来说,当使用多步表单时,最好使用受控组件并维护父组件中的状态

    【讨论】:

    • 嘿,如果每个表单都有一个输入字段,那么您的解决方案很好,在我的情况下,我在每个表单中有多个输入字段,假设例如我的表单一中有 2 个输入,即年龄如此在字段数组的主要组件中,我传递了第二个值,即年龄,所以它工作正常,但是当我回来时,即从 2 到 1,两个输入字段所采用的值是相同的,即我传入的值是你的年龄也是一样的。
    • 嗯...给我你输入年龄的密码框,我会修复它
    • codesandbox.io/s/determined-glade-ei1in?file=/src/App.js 嘿,这是我的代码沙箱,我刚刚以年龄为例,重点是表单可以有多个字段,任何表单都不会有一个字段。
    • 刚刚检查过 - 在您的示例中, uname 和 age 采用相同的值,因为您错误地设置了年龄输入 defaultValue。即您使用了 defaultValues.uname 而不是 .age。所以对于年龄输入做defaultValue={defaultValues &amp;&amp; defaultValues.age} ...希望现在一切都好...
    • 嘿,我没有得到您的解决方案,请您分享codesandbox 链接。
    猜你喜欢
    • 1970-01-01
    • 2019-09-18
    • 2020-11-11
    • 1970-01-01
    • 2022-07-05
    • 2021-09-14
    • 2020-04-09
    • 1970-01-01
    • 2018-11-28
    相关资源
    最近更新 更多