问题
I am having 3 materialUI TextFields which are render n number of times (n is an integer input from the user before rendering the form field, where I stored it in a variable named groupMembersCount). I am getting it dynamically rendered by this way:
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>
);
}
What if I filled the number (groupMembersCount) and then filled those form fields and after filling, I modified groupMembersCount (either increase or decrease), in case of increase I want the values that user filled should retain and if decreased, form fields values should clear out. I tried passing values from groupDetails array to form in "value" prop but it shows an error because the index I an writing/passing the values initially doesn't exist at that index.
回答1:
You need set value from groupDetails
that was stored before using useState
. Please check this example:
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 DynamicGroupMember3() {
const [groupMembersCount, setGroupMembersCount] = useState(0);
const [show, setShow] = useState(false);
const [errorText, setErrorText] = useState([]);
const [showState, setShowState] = useState(false);
const [groupDetails, setGroupDetails] = useState([
{fullName: "", phoneNo: "", gender: ""},
]);
const [state, setState] = React.useState({
idProof: "",
noOfPeople: "",
bookingId: "",
detailsOfPeople: [],
});
function handleChange(event, index) {
event.preventDefault();
console.log(errorText.length, 'length');
if (event.target.name === "phoneNo") {
// do validation here
let valid = false;
if (isNaN(event.target.value)) {
let arr = [...errorText];
arr[index] = 'Invalid ' + event.target.name;
setErrorText(arr);
} else {
let arr = [...errorText];
arr[index] = '';
setErrorText(arr);
}
}
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) => {
if (isNaN(event.target.value)) {
alert('Please enter number');
return;
}
if (event.target.value !== '') {
let noOfMember = parseInt(event.target.value);
let errors = new Array(noOfMember);
setErrorText(errors);
if (groupMembersCount > noOfMember) {
let newGroup = [];
groupDetails.map((group, index) => {
if (index < noOfMember) {
newGroup.push(group);
}
});
setGroupDetails(newGroup);
}
setGroupMembersCount(noOfMember);
}
}}/>
{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"
value={groupDetails[i] ? groupDetails[i].fullName : ''}
onChange={(event) => {
handleChange(event, i)
}}
/>
<TextField
id={`phoneNo${i + 1}`}
name="phoneNo"
variant="outlined"
margin="none"
label="Mobile Number"
value={groupDetails[i] ? groupDetails[i].phoneNo : ''}
onChange={(event) => {
handleChange(event, i)
}}
error={errorText[i] !== '' && errorText[i] !== undefined}
helperText={errorText[i]}
/>
<Select
id={`gender${i + 1}`}
name="gender"
variant="outlined"
margin="none"
label="Gender"
value={groupDetails[i] ? groupDetails[i].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, index) =>
<Card key={index}>
<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
}
<Button onClick={() => {
console.log(groupDetails, 'groupDetails');
setState({
idProof: "XYZ123",
noOfPeople: groupDetails.length,
bookingId: "boking-4434",
detailsOfPeople: groupDetails
});
console.log(groupDetails, 'groupDetails');
setShowState(true);
}}>Show STATE</Button>
{
showState ?
<Card>
<CardContent>
<Typography color="textSecondary" gutterBottom>
Id Proof: {state.idProof}
</Typography>
<Typography variant="h5" component="h2">
No Of People: {state.noOfPeople}
</Typography>
<Typography color="textSecondary">
Booking Id: {state.bookingId}
</Typography>
</CardContent>
</Card> : null
}
</div>
);
}
来源:https://stackoverflow.com/questions/62121702/populate-dynamically-rendered-form-fields-in-react