首页 > 解决方案 > 动态渲染表单元素并将它们保存在 ReactJS 中的数组中

问题描述

我有 3 个materialUI文本字段,我想渲染n次(在渲染表单字段之前,n将是用户输入的整数,这里我将它存储在名为groupMembersCount的变量中)。我在 ReactJS 中使用功能组件定义一个带有 useState 钩子的数组

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. 名称属性中具有性别的表单字段(TextField)之一,我无法使用select创建下拉列表(写入此处显示的内容会导致空白屏幕)所以我把它注释掉了。2. 在for 循环内的handleGroupName处理程序中,错误显示为:UserDetails.jsx:434 Uncaught TypeError: Cannot read property 'getAttribute' of undefined。3.我是反应功能组件的新手,没有太多经验,任何人都可以提出一些更好的方法来从这些表单字段中获取每个渲染的值并将它们作为一个对象并存储在主数组中的不同索引处,主数组groupDetails的结构定义了它最后的样子。

标签: javascriptreactjsmaterial-uireact-hooksreact-functional-component

解决方案


请尝试这个示例,我在该示例中输入number of member在组中定义的输入。然后显示number of input groups(姓名、电话和性别)。填写信息后,如果您单击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>
    );
}

推荐阅读