簡體   English   中英

React:DOM 不以動態形式反映組件狀態

[英]React: DOM not reflecting component state in dynamic form

這是學生詳細信息的動態表單,可以使用“ + ”和“ X ”按鈕添加或刪除新的學生字段。 (即,學生字段的數量由用戶決定)。 在這里, App => Parent Component & StudentsFormElement => Child Component。

問題:任何“ X ”按鈕在單擊時只會刪除最后一個學生字段(在 DOM 中),而不是應該刪除的字段。 但最重要的是,父組件狀態會正確更改,並從中刪除正確的學生詳細信息。 此狀態更改未反映在 DOM 中。

代碼和盒子: 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>
    )
  }
}

我嘗試過的事情:在處理onStudentsChange() 中的“X”按鈕后,我嘗試過 this.forceUpdate() 但它沒有任何區別。

再次, codesandbox: https ://codesandbox.io/s/peaceful-spence-1j3nv ? fontsize =14& hidenavigation =1& theme = dark

如果你看看下面的代碼:

<form>{this.state.studentsFormElements}</form>

我剛剛更改為Form並且它工作正常。

您必須向StudentsFormElement添加一個key道具。 如果您打開控制台,您可以看到 React 拋出錯誤。 我做了兩個改變,

  1. 第 12 行:
studentsFormElementsTemp.push(<StudentsFormElement id="0" key={0} student={this.state.STUDENTS[0]} onStudentsChange={this.onStudentsChange} />)
  1. 第 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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM