动态渲染表单元素并将它们保存在 ReactJS 中的数组中

Dynamically rendering form elements and saving them in an array in ReactJS

我有 3 个 materialUI TextFields,我想渲染 n 次(n 将是用户在呈现表单字段之前输入的整数,这里我将其存储在名为 groupMembersCount) 的变量中。 我在 ReactJS 中使用功能组件定义一个 array with useState hooks as:

const [groupDetails, setGroupDetails] = React.useState([
    { fullName: "", phoneNo: "", gender: "" },
  ]);

这将是我的主数组,用于在各自的索引处保存所有 3 个值(用户输入)。 我尝试通过这种方法动态返回那些 3 materialUI TextField

{Array.apply(null, { length: groupMembersCount }).map(
                (e, i) => (
                  <div key={i}>
                    <strong>Member #{i + 1}</strong>
                    <div className="getIndex" name={i + 1}>
                      <TextField
                        id={Math.random()}
                        name="Name"
                        variant="outlined"
                        margin="none"
                        label="Name"
                        onChange={handleGroupName}
                      />
                      <TextField
                        id={Math.random()}
                        name="phoneNo"
                        variant="outlined"
                        margin="none"
                        label="Mobile Number"
                        onChange={handleGroupPhoneNo}
                      />
                      <TextField
                        id={Math.random()}
                        name="gender"
                        variant="outlined"
                        margin="none"
                        label="Gender"
                        onChange={handleGroupGender}
                        select
                      >
                        <option value="MALE">Male</option>
                        <option value="FEMALE">Female</option>
                        <option value="OTHER">Other</option>
                      </TextField>
                    </div>
                  </div>
                )
              )}

现在在名称处理程序中 handleGroupName 我这样做是为了获取 div(从存储索引的名称属性中获取索引以推送此值在主数组 groupDetails):

const handleGroupName = (event) => {
    let elem = document.getElementsByClassName("getIndex");  // get div 
    for (var i = 0; i < groupMembersCount; i++) {
      console.log("index is: ", elem[i].getAttribute('name')); // get the index number 
    }
  };

完成所有这些后,我遇到了一些问题: 1. name 属性中带有性别的表单字段 (TextField) 之一,我无法使用 select 创建下拉列表(写入此处显示的内容会导致空白屏幕)所以我把它注释掉了。 2. 在 for 循环内的 handleGroupName 处理程序中,它显示错误为:UserDetails.jsx:434 Uncaught TypeError: Cannot read 属性 'getAttribute' of undefined。 3. 我是 React 功能组件的新手,没有太多经验,谁能建议一些更好的方法来从每个渲染的表单字段中获取值,并将它们作为对象合并并存储在主数组中的不同索引处,主数组的结构 groupDetails 定义了它最后的样子。

请试试这个例子,我输入了在组中定义 number of member 的输入。然后显示 number of input groups(姓名,phone 和性别)。填写信息后,如果您单击 Show 按钮,您将看到结果。

import TextField from "@material-ui/core/TextField";
import React, {useState} from "react";
import Select from "@material-ui/core/Select";
import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import Typography from "@material-ui/core/Typography";

export default function DynamicGroupMember() {
    const [groupMembersCount, setGroupMembersCount] = useState(0);
    const [show, setShow] = useState(false);
    const [groupDetails, setGroupDetails] = useState([
        {fullName: "", phoneNo: "", gender: ""},
    ]);

    function handleChange(event, index) {
        console.log(event.target.value, index);
        let newArr = [...groupDetails]; // copying the old datas array
        let item = newArr[index];
        item = {...item, [event.target.name]: event.target.value};
        newArr[index] = item;

        setGroupDetails(newArr);
    }

    return (
        <div>
            Number of Group: <TextField name="groupMembersCount" onChange={(event) => {
            setGroupMembersCount(event.target.value)
        }}/>
            {Array.apply(null, {length: groupMembersCount}).map(
                (e, i) => (
                    <div key={i}>
                        <strong>Member #{i + 1}</strong>
                        <div className="getIndex" name={i + 1}>
                            <TextField
                                id={`name${i + 1}`}
                                name="fullName"
                                variant="outlined"
                                margin="none"
                                label="Name"
                                onChange={(event) => {
                                    handleChange(event, i)
                                }}
                            />
                            <TextField
                                id={`phoneNo${i + 1}`}
                                name="phoneNo"
                                variant="outlined"
                                margin="none"
                                label="Mobile Number"
                                onChange={(event) => {
                                    handleChange(event, i)
                                }}
                            />
                            <Select
                                id={`gender${i + 1}`}
                                name="gender"
                                variant="outlined"
                                margin="none"
                                label="Gender"
                                onChange={(event) => {
                                    handleChange(event, i)
                                }}
                            >
                                <option value="MALE">Male</option>
                                <option value="FEMALE">Female</option>
                                <option value="OTHER">Other</option>
                            </Select>
                        </div>
                    </div>
                )
            )}
            <Button onClick={() => {
                setShow(true)
            }}>Show</Button>
            {
                show ?
                    groupDetails.map(member =>
                        <Card>
                        <CardContent>
                            <Typography color="textSecondary" gutterBottom>
                                {member.fullName}
                            </Typography>
                            <Typography variant="h5" component="h2">
                                {member.phoneNo}
                            </Typography>
                            <Typography color="textSecondary">
                                {member.gender}
                            </Typography>
                        </CardContent>
                    </Card>) : null
            }
        </div>
    );
}