2

我正在尝试使用 React-hooks-form 构建一个多步骤表单,其中一个步骤有一个提示选择的选择菜单和两个其他文本字段。

较大形式中的步骤具有:

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import useForm from "react-hook-form";
import { withRouter } from "react-router-dom";
import { useStateMachine } from "little-state-machine";
import updateAction from "./updateAction";
import { Form, Button, Divider, Layout, Typography, Skeleton, Switch, Card, Icon, Avatar } from 'antd';
import Select from "react-select";



const { Content } = Layout 
const { Text, Paragraph } = Typography;
const { Meta } = Card;





const defaultValue = {
  explain: "",
  managementPlan: ""
};

const issueOptions = [
  { value: "riskofharm", label: "Risk of harm" },
  { value: "informedconsent", label: "Informed consent" },
  { value: "anon", label: "Anonymity and Confidentiality" },
  { value: "deceptive", label: "Deceptive practices" },
  { value: "withdrawal", label: "Right to withdraw" },
  { value: "none", label: "No ethics considerations" }
];

const Budget = props => {
  const [ethics, setEthics] = useState([]);
  const [issues, setIssues] = useState([]);
  const { action } = useStateMachine(updateAction);
  const { register, handleSubmit, setValue, getValues, clearError } = useForm();

  useEffect(() => {
    register({ name: "issues" });
  }, [register]);

  // const onSubmit = data => {
  //   console.log("submit", data);
  const onSubit = data => {
    // console.log("submit", data);
    // console.log("combined", formValues);


    // combine your ethicsIssue to formValues
    const { ethics, issues } = data;
    const formValues = {
      ethics: ethics.map((ethic, index) => ({
        ...ethic,
        issue: issues[index]
      }))
    };
    action(data);
    props.history.push("./ProposalOutcomes");

  };               



  const handleChange = index => selectecIssue => {
    const issuesCopy = [...issues];
    issuesCopy[index] = selectecIssue;

    setIssues(issuesCopy);
    setValue("issues", issuesCopy);
  };

  const addEthic = async () => {
    setEthics([...ethics, defaultValue]);
  };

  const removeEthic = index => () => {
    // get values
    const { ethics, issues } = getValues({ nest: true });

    // create a copy
    const newEthics = [...(ethics || [])];
    const newIssues = [...(issues || [])];

    // remove by index
    newEthics.splice(index, 1);
    newIssues.splice(index, 1);

    // update values
    setEthics(newEthics);
    setIssues(newIssues);

    for (let i = 0; i < newEthics.length; i++) {
      // we register the field using ethics[i].explain
      // therefore, we need to setValue that way
      setValue(`ethics[${i}].explain`, newEthics[i].explain);
      setValue(`ethics[${i}].managementPlan`, newEthics[i].managementPlan);
    }

    // same goes with issue
    setValue("issues", newIssues);
  };

  const clearEthics = () => {
    setEthics([]);
    setIssues([]);
    setValue("issues", []);
    clearError();
  };

  return (
    <div>
      <Content
        style={{
          background: '#fff',
          padding: 24,
          margin: "auto",
          minHeight: 280,
          width: '70%'
        }}
      >
      <Paragraph>
        <h2>Design Studio</h2>
        <h4 style={{ color: '#506e8d'}}>Design a Research Proposal</h4>
        </Paragraph>
        <Divider />

        <h2>Part 10: Ethics</h2>


    <form onSubmit={handleSubmit(onSubit)}>
      {ethics.map((_, index) => {
        const fieldName = `ethics[${index}]`;

        return (
          <fieldset name={fieldName} key={fieldName}>
            <label>
              Issue {index}:
              <Select
                placeholder="Select One"
                value={issues[index]}
                options={issueOptions}
                onChange={handleChange(index)}
              />
            </label>

            <label>
              Explain {index}:
              <input type="text" name={`${fieldName}.explain`} ref={register} />
            </label>

            <label>
              Management Plan {index}:
              <input
                type="text"
                name={`${fieldName}.managementPlan`}
                ref={register}
              />
            </label>

            <Button type="danger" style={{ marginBottom: '20px', float: 'right'}} onClick={removeEthic(index)}>
              Remove Ethic
            </Button>
          </fieldset>
        );
      })}
      <div className="action">
        <Button type="primary" style={{ marginBottom: '20px'}} onClick={addEthic}>
          Add Ethic
        </Button>
        <br />
        <Button type="button" style={{ marginBottom: '20px'}} onClick={clearEthics}>
          Clear Ethics
        </Button>
      </div>
      <input type="submit" value="next - outcomes" />

    </form>
    </Content>
    </div>
  );
}



export default withRouter(Budget);

我无法使用来自 3 个字段的内容生成单个数组。

目前,我得到了一个如下所示的 json 数据包(一个涉及道德问题,另一个涉及问题):

"ethics": [
{
"explain": "hel",
"managementPlan": "hello"
},
{
"explain": "hiiii",
"managementPlan": "hi"
}
]
,
"issues": [
{
"value": "withdrawal",
"label": "Right to withdraw"
},
{
"value": "deceptive",
"label": "Deceptive practices"
}
]

我被困在这个表格上,出现一个错误,上面写着:无法读取未定义的地图。

错误消息突出显示指向此行的问题:

  {ethics.map((_, index) => {

我期待 on submit 函数将单个数组中的 3 个表单字段推送到 updateAction,但这没有发生,我看不出我需要做什么才能使其正常工作。

有没有人使用 react-hook-forms 中的字段数组成功地将选择菜单与可重复的表单字段集成在一起?

4

1 回答 1

2

我已经为 Field Array 添加了一个新部分,我们还在为useFieldArray. https://react-hook-form.com/advanced-usage#FieldArrays

这是一个代码片段:

import React, { useState } from "react";
import { useForm } from "react-hook-form";

function createArrayWithNumbers(length) {
  return Array.from({ length }, (_, k) => k + 1);
}

export default function App() {
  const { register, handleSubmit } = useForm();
  const [size, setSize] = useState(1);
  const onSubmit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {createArrayWithNumbers(size).map(index => {
        return (
          <>
            <label htmlFor="firstName">First Name</label>
            <input
              name={`firstName[${index}]`}
              placeholder="first name"
              ref={register({ required: true })}
            />

            <label htmlFor="lastName">Last Name</label>
            <input
              name={`lastName[${index}]`}
              placeholder="last name"
              ref={register({ required: true })}
            />
          </>
        );
      })}

      <button type="button" onClick={() => setSize(size + 1)} >
        Add Person
      </button>

      <input type="submit" />
    </form>
  );
}

此代码框还显示了高级用法:https ://codesandbox.io/s/react-hook-form-field-array-advanced-with-delete-insert-append-edit-l19pz

于 2020-01-10T10:48:44.677 回答