javascript - React-hooks-form - 迭代字段数组,其中使用 useState 设置其中一个字段

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

我正在尝试使用 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"
}
]

我被困在这个表单上,并出现错误:无法读取未定义的 map 。

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

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

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

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

最佳答案

我为字段数组添加了一个新部分,并且我们还在为 useFieldArray 开发一个新的自定义 Hook 。 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>
  );
}

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

关于javascript - React-hooks-form - 迭代字段数组,其中使用 useState 设置其中一个字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58794181/

相关文章:

javascript - 如何通过Enzyme获取依赖组件元素?

javascript - React useState 钩子(Hook)不触发子组件的重新渲染

javascript - Polymer - 核心动画页面中的内容标签不占用高度

javascript - 链接方法并将结果传递给 Javascript 中的下一个链接函数

json - 从传统的 Laravel/Rails 应用程序迁移到 React.js 生态系统。需要在前端进行数据管理

javascript - 我可以为不同的页面使用多个布局吗?

javascript - React Hooks 中的正则表达式

javascript - useEffect,覆盖if语句

javascript - 未捕获的语法错误 : Unexpected token ILLEGAL in jQuery string

php - 使用 PHP 和 Javascript 记录用户操作