为什么 DOM 没有在我的动态表单中反映我的组件状态
Why is the DOM not reflecting my component state in my dynamic form
这是学生详细信息的动态表单,可以使用“+”和“X[=41= 添加或删除新的学生字段]' 纽扣。 (即,学生字段的数量由用户决定)。这里,App => 父组件 & StudentsFormElement => 子组件。
问题:任何“X”按钮在单击时仅删除最后一个学生字段(在DOM) 而不是应该删除的那个。但最重要的是,父组件状态会正确更改,并从中删除正确的学生详细信息。此状态更改未反映在 DOM.
中
codesandbox: https://codesandbox.io/s/peaceful-spence-1j3nv?fontsize=14&hidenavigation=1&theme=dark
应用程序组件:
class App extends React.Component {
constructor(props) {
super(props)
let studentsFormElementsTemp = []
let tempSTUDENTS = {0: ["", ""]}
this.state = {
STUDENTS: tempSTUDENTS
}
studentsFormElementsTemp.push(<StudentsFormElement id="0" student={this.state.STUDENTS[0]} onStudentsChange={this.onStudentsChange} />)
this.state = {
studentsFormElements: studentsFormElementsTemp,
studentsElementsIdArray: [0],
STUDENTS: tempSTUDENTS
}
}
render() {
return (
<div>
<h2 style={{textAlign: "center", display: "inline-block"}}>Students</h2><Button id="+" style={{display: "inline-block"}} variant="success" onClick={this.onStudentsChange}>+</Button>
<form>
{this.state.studentsFormElements}
</form>
<p>{JSON.stringify(this.state.STUDENTS)}</p>
</div>
)
}
onStudentsChange = (e) => {
if (e.target.name === "studentId" || e.target.name === "studentName") { //HANDLING TYPED CHARACTERS.
let tempSTUDENTS = this.state.STUDENTS
if (e.target.name === "studentId") {
tempSTUDENTS[e.target.id][0] = e.target.value
}
else {
tempSTUDENTS[e.target.id][1] = e.target.value
}
this.setState({
STUDENTS: tempSTUDENTS
})
} else {
let studentsFormElementsTemp = this.state.studentsFormElements
let studentsElementsIdArrayTemp = this.state.studentsElementsIdArray
let tempSTUDENTS = this.state.STUDENTS
if (e.target.id === "+") { //ADDING (+) STUDENT
tempSTUDENTS[studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1] = ["", ""]
this.setState({
STUDENTS: tempSTUDENTS
})
studentsFormElementsTemp.push(<StudentsFormElement id={studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1} student={this.state.STUDENTS[studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1]} onStudentsChange={this.onStudentsChange} />)
studentsElementsIdArrayTemp.push(studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1)
this.setState({
studentsFormElements: studentsFormElementsTemp,
studentsElementsIdArray: studentsElementsIdArrayTemp
})
} else { //DELETING STUDENT (X)
let studentIndex = studentsElementsIdArrayTemp.indexOf(parseInt(e.target.id))
studentsFormElementsTemp.splice(studentIndex, 1)
studentsElementsIdArrayTemp.splice(studentIndex, 1)
delete tempSTUDENTS[e.target.id]
this.setState({
studentsFormElements: studentsFormElementsTemp,
studentsElementsIdArray: studentsElementsIdArrayTemp,
STUDENTS: tempSTUDENTS
})
}
}
}
}
StudentsFormElement 组件:
class StudentsFormElement extends React.Component {
render() {
return (
<InputGroup className="mb-3">
<FormControl name="studentId" id={this.props.id} defaultValue={this.props.student[0]} placeholder="Id" onChange={this.props.onStudentsChange} />
<FormControl name="studentName" id={this.props.id} defaultValue={this.props.student[1]} placeholder="Name" onChange={this.props.onStudentsChange} />
<InputGroup.Append style={{display: "inline-block"}}>
<Button id={this.props.id} variant="danger" onClick={this.props.onStudentsChange}>X</Button>
</InputGroup.Append>
</InputGroup>
)
}
}
我尝试过的事情: 我在处理 'X' 之后就尝试了 this.forceUpdate() onStudentsChange() 中的按钮,但没有任何区别。
同样,codesandbox: https://codesandbox.io/s/peaceful-spence-1j3nv?fontsize=14&hidenavigation=1&theme=dark
如果你看下面的代码:
<form>{this.state.studentsFormElements}</form>
我刚刚更改为 Form,它工作正常。
您必须向 StudentsFormElement
添加一个 key
属性。如果你打开控制台,你可以看到 React 抛出一个错误。我做了两个更改,
- 第 12 行:
studentsFormElementsTemp.push(<StudentsFormElement id="0" key={0} student={this.state.STUDENTS[0]} onStudentsChange={this.onStudentsChange} />)
- 第 53 行:
studentsFormElementsTemp.push(<StudentsFormElement id={studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1}
key={studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1}
student={this.state.STUDENTS[studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1]} onStudentsChange={this.onStudentsChange} />)
我可以指出其他重构,但它们与提出的问题无关。
您要求的其他重构,
import React from "react";
import { InputGroup, FormControl, Button, Form } from "react-bootstrap";
class App extends React.Component {
constructor(props) {
super(props);
let identifier = 0;
this.state = {
students: [
{
identifier: identifier++,
id: "",
name: ""
}
],
identifier
};
}
addStudent = () => {
this.setState((prevState) => {
const newStudents = [...prevState.students];
newStudents.push({
identifier: prevState.identifier,
id: "",
name: ""
});
return {
identifier: prevState.identifier + 1,
students: newStudents
};
});
};
onDeleteStudent = (identifier) => {
console.log(identifier);
const filteredStudents = this.state.students.filter(
(student) => student.identifier !== identifier
);
this.setState({
students: filteredStudents
});
};
onInputChange = (event, fieldName, identifier) => {
const newStudents = [...this.state.students];
newStudents.forEach((student) => {
if (student.identifier === identifier) {
student[fieldName] = event.target.value;
}
});
this.setState(newStudents);
};
render() {
return (
<div>
<h2 style={{ textAlign: "center", display: "inline-block" }}>
Students
</h2>
<Button
id="+"
style={{ display: "inline-block" }}
variant="success"
onClick={this.addStudent}
>
+
</Button>
<Form>
{this.state.students.map((student, index) => (
<StudentsFormElement
key={student.identifier}
student={student}
onInputChange={this.onInputChange}
onDeleteStudent={this.onDeleteStudent}
/>
))}
</Form>
<p>{JSON.stringify(this.state.students)}</p>
</div>
);
}
}
class StudentsFormElement extends React.Component {
render() {
const { identifier, id, name } = this.props.student;
return (
<InputGroup className="mb-3">
<FormControl
name="id"
defaultValue={id}
placeholder="Id"
onChange={(event) => {
this.props.onInputChange(event, "id", identifier);
}}
/>
<FormControl
name="name"
defaultValue={name}
placeholder="Name"
onChange={(event) => {
this.props.onInputChange(event, "name", identifier);
}}
/>
<InputGroup.Append style={{ display: "inline-block" }}>
<Button
variant="danger"
onClick={() => {
this.props.onDeleteStudent(identifier);
}}
>
X
</Button>
</InputGroup.Append>
</InputGroup>
);
}
}
export default App;
这是学生详细信息的动态表单,可以使用“+”和“X[=41= 添加或删除新的学生字段]' 纽扣。 (即,学生字段的数量由用户决定)。这里,App => 父组件 & StudentsFormElement => 子组件。
问题:任何“X”按钮在单击时仅删除最后一个学生字段(在DOM) 而不是应该删除的那个。但最重要的是,父组件状态会正确更改,并从中删除正确的学生详细信息。此状态更改未反映在 DOM.
中codesandbox: https://codesandbox.io/s/peaceful-spence-1j3nv?fontsize=14&hidenavigation=1&theme=dark
应用程序组件:
class App extends React.Component {
constructor(props) {
super(props)
let studentsFormElementsTemp = []
let tempSTUDENTS = {0: ["", ""]}
this.state = {
STUDENTS: tempSTUDENTS
}
studentsFormElementsTemp.push(<StudentsFormElement id="0" student={this.state.STUDENTS[0]} onStudentsChange={this.onStudentsChange} />)
this.state = {
studentsFormElements: studentsFormElementsTemp,
studentsElementsIdArray: [0],
STUDENTS: tempSTUDENTS
}
}
render() {
return (
<div>
<h2 style={{textAlign: "center", display: "inline-block"}}>Students</h2><Button id="+" style={{display: "inline-block"}} variant="success" onClick={this.onStudentsChange}>+</Button>
<form>
{this.state.studentsFormElements}
</form>
<p>{JSON.stringify(this.state.STUDENTS)}</p>
</div>
)
}
onStudentsChange = (e) => {
if (e.target.name === "studentId" || e.target.name === "studentName") { //HANDLING TYPED CHARACTERS.
let tempSTUDENTS = this.state.STUDENTS
if (e.target.name === "studentId") {
tempSTUDENTS[e.target.id][0] = e.target.value
}
else {
tempSTUDENTS[e.target.id][1] = e.target.value
}
this.setState({
STUDENTS: tempSTUDENTS
})
} else {
let studentsFormElementsTemp = this.state.studentsFormElements
let studentsElementsIdArrayTemp = this.state.studentsElementsIdArray
let tempSTUDENTS = this.state.STUDENTS
if (e.target.id === "+") { //ADDING (+) STUDENT
tempSTUDENTS[studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1] = ["", ""]
this.setState({
STUDENTS: tempSTUDENTS
})
studentsFormElementsTemp.push(<StudentsFormElement id={studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1} student={this.state.STUDENTS[studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1]} onStudentsChange={this.onStudentsChange} />)
studentsElementsIdArrayTemp.push(studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1)
this.setState({
studentsFormElements: studentsFormElementsTemp,
studentsElementsIdArray: studentsElementsIdArrayTemp
})
} else { //DELETING STUDENT (X)
let studentIndex = studentsElementsIdArrayTemp.indexOf(parseInt(e.target.id))
studentsFormElementsTemp.splice(studentIndex, 1)
studentsElementsIdArrayTemp.splice(studentIndex, 1)
delete tempSTUDENTS[e.target.id]
this.setState({
studentsFormElements: studentsFormElementsTemp,
studentsElementsIdArray: studentsElementsIdArrayTemp,
STUDENTS: tempSTUDENTS
})
}
}
}
}
StudentsFormElement 组件:
class StudentsFormElement extends React.Component {
render() {
return (
<InputGroup className="mb-3">
<FormControl name="studentId" id={this.props.id} defaultValue={this.props.student[0]} placeholder="Id" onChange={this.props.onStudentsChange} />
<FormControl name="studentName" id={this.props.id} defaultValue={this.props.student[1]} placeholder="Name" onChange={this.props.onStudentsChange} />
<InputGroup.Append style={{display: "inline-block"}}>
<Button id={this.props.id} variant="danger" onClick={this.props.onStudentsChange}>X</Button>
</InputGroup.Append>
</InputGroup>
)
}
}
我尝试过的事情: 我在处理 'X' 之后就尝试了 this.forceUpdate() onStudentsChange() 中的按钮,但没有任何区别。
同样,codesandbox: https://codesandbox.io/s/peaceful-spence-1j3nv?fontsize=14&hidenavigation=1&theme=dark
如果你看下面的代码:
<form>{this.state.studentsFormElements}</form>
我刚刚更改为 Form,它工作正常。
您必须向 StudentsFormElement
添加一个 key
属性。如果你打开控制台,你可以看到 React 抛出一个错误。我做了两个更改,
- 第 12 行:
studentsFormElementsTemp.push(<StudentsFormElement id="0" key={0} student={this.state.STUDENTS[0]} onStudentsChange={this.onStudentsChange} />)
- 第 53 行:
studentsFormElementsTemp.push(<StudentsFormElement id={studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1}
key={studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1}
student={this.state.STUDENTS[studentsElementsIdArrayTemp[studentsElementsIdArrayTemp.length - 1] + 1]} onStudentsChange={this.onStudentsChange} />)
我可以指出其他重构,但它们与提出的问题无关。
您要求的其他重构,
import React from "react";
import { InputGroup, FormControl, Button, Form } from "react-bootstrap";
class App extends React.Component {
constructor(props) {
super(props);
let identifier = 0;
this.state = {
students: [
{
identifier: identifier++,
id: "",
name: ""
}
],
identifier
};
}
addStudent = () => {
this.setState((prevState) => {
const newStudents = [...prevState.students];
newStudents.push({
identifier: prevState.identifier,
id: "",
name: ""
});
return {
identifier: prevState.identifier + 1,
students: newStudents
};
});
};
onDeleteStudent = (identifier) => {
console.log(identifier);
const filteredStudents = this.state.students.filter(
(student) => student.identifier !== identifier
);
this.setState({
students: filteredStudents
});
};
onInputChange = (event, fieldName, identifier) => {
const newStudents = [...this.state.students];
newStudents.forEach((student) => {
if (student.identifier === identifier) {
student[fieldName] = event.target.value;
}
});
this.setState(newStudents);
};
render() {
return (
<div>
<h2 style={{ textAlign: "center", display: "inline-block" }}>
Students
</h2>
<Button
id="+"
style={{ display: "inline-block" }}
variant="success"
onClick={this.addStudent}
>
+
</Button>
<Form>
{this.state.students.map((student, index) => (
<StudentsFormElement
key={student.identifier}
student={student}
onInputChange={this.onInputChange}
onDeleteStudent={this.onDeleteStudent}
/>
))}
</Form>
<p>{JSON.stringify(this.state.students)}</p>
</div>
);
}
}
class StudentsFormElement extends React.Component {
render() {
const { identifier, id, name } = this.props.student;
return (
<InputGroup className="mb-3">
<FormControl
name="id"
defaultValue={id}
placeholder="Id"
onChange={(event) => {
this.props.onInputChange(event, "id", identifier);
}}
/>
<FormControl
name="name"
defaultValue={name}
placeholder="Name"
onChange={(event) => {
this.props.onInputChange(event, "name", identifier);
}}
/>
<InputGroup.Append style={{ display: "inline-block" }}>
<Button
variant="danger"
onClick={() => {
this.props.onDeleteStudent(identifier);
}}
>
X
</Button>
</InputGroup.Append>
</InputGroup>
);
}
}
export default App;