Динамический рендеринг элементов формы и сохранение их в массиве в ReactJS - PullRequest
1 голос
/ 26 мая 2020

У меня есть 3 materialUI TextFields, которые я хочу отобразить 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 (чтобы получить index [из его атрибута name], который сохраняет индекс до pu sh это значение в основном массиве 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. В обработчике handleGroupName внутри для l oop ошибка отображается как: UserDetails.jsx: 434 Uncaught TypeError: невозможно прочитать свойство getAttribute, равное undefined. 3. Я новичок в реагировании на функциональный компонент, у меня мало опыта в этом, может ли кто-нибудь предложить более эффективные способы получения значений из этих полей формы для каждого рендеринга и объединить их как объект и сохранить в другом индексе в основном массиве, структура основного массива groupDetails определяет, как он должен выглядеть в конце.

1 Ответ

1 голос
/ 27 мая 2020

Пожалуйста, попробуйте этот пример, где я использую ввод, который определяет 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>
    );
}
...