使用 shouldComponentUpdate 时子组件被删除

Child component is deleted when using shouldComponentUpdate

我有 3 个组成部分:SemesterList、Semester 和 Course。
SemesterList 包含状态(包含所有学期及其内容的数组)。
在 Course 组件中,我创建了一个 shouldComponentUpdate() 方法,以避免呈现未更改的课程。如果没有这个方法,所有学期的所有课程都会重新渲染。

但是,添加课程后,当我修改除了添加的课程以外的其他课程时,添加的课程被删除了!
当我添加多门课程然后尝试修改最初存在的课程时,也会发生同样的事情。
我不知道为什么,但我认为这是由于 shouldComponentUpdate() 方法造成的。

这是 shouldComponentUpdate():

shouldComponentUpdate(nextProps, nextState) {
   if (JSON.stringify(this.props.course) === JSON.stringify(nextProps.course)) {
      return false;
   }

   return true;
}

我在 React 文档中读到 JSON.stringify() 很昂贵,但我暂时忽略它。

学期部分render方法部分:

{semester.courses.map(
   course => (
     <Course
       key={course.id}
       course={course}  
       semester={semester}
       onInputChange={onInputChange}
       onDeleteCourse={onDeleteCourse}
    />
  )
)}

这是按下字符时调用的 onInputChange() 函数和添加课程时调用的 handleAddCourse .

  handleInputChange = (event, course, semester) => {
    const { name, value } = event.target;
    var semesters = [...this.state.semesters], semesterCourses = [...semester.courses];
    var course = { ...course };
    course[name] = value;

    semesterCourses[course.id-1] = course;
    semester.courses = [...semesterCourses];

    semesters[semester.number-1] = semester;
    this.setState({ semesters });
  }

  handleAddCourse = semester => {
    var semesters = [...this.state.semesters], semester = { ...semester };
    var semesterCourses = [...semester.courses];
    const semesterIndex = semester.number - 1;

    semesterCourses.push({
      // new course's id is obtained by incrementing last course's id which is the number of courses
      id: semesterCourses.length + 1,
      name: '',
      credit: 0,
      markOver100: 0.0,
      grade: '',
    });
    semester.courses = semesterCourses;
    semesters[semesterIndex] = semester;

    this.setState({ semesters });
  }

正如我之前所说,我认为问题出在 shouldComponentUpdate() 方法中,因为当它被注释掉时,一切都按预期工作。

您正在将 coursesemester 属性传递给 <Course> 组件,但您的 JSON.stringify 比较仅检查 course.

每次 add/change 一门课程,您都会使用扩展运算符创建 semestersemesterCourses 的新副本。因此,您现有的 <Course> 未重新渲染的组件将保留旧的 semester。这就是当您更改任何现有课程时新添加的课程消失的原因,因为旧 semestersemesterCourses 不包含新添加的课程。

因此,要解决此问题,您还需要将 semester 添加到您的比较中

if (JSON.stringify(this.props.course) === JSON.stringify(nextProps.course) &&
    JSON.stringify(this.props.semester) === JSON.stringify(nextProps.semester)
   ) {
      return false;
}

以上代码可以解决您的问题,但不会阻止其他课程的重新呈现。

更好的设计是不将 semester 属性传递给 <Course> 组件。 但如果这是不可避免的,那么也许不要创建 semestersemesterCourses 的新副本并保持你的 shouldComponentUpdate 不变。

handleInputChange = (event, course, semester) => {
  const { name, value } = event.target;
  var semesters = [...this.state.semesters];
  var course = { ...course };
  course[name] = value;
  semester.courses[course.id-1] = course;
  this.setState({ semesters });
}

handleAddCourse = semester => {
  var semesters = [...this.state.semesters];

  semester.courses.push({
    // new course's id is obtained by incrementing last course's id which is the number of courses
    id: semester.courses.length + 1,
    name: '',
    credit: 0,
    markOver100: 0.0,
    grade: '',
  });  
  this.setState({ semesters });
}

您甚至不需要创建 var semesters = [...this.state.semesters];

的新副本
handleInputChange = (event, course, semester) => {
  const { name, value } = event.target;
  course[name] = value;
  this.setState(this.state); // enough to trigger re-render
}

handleAddCourse = semester => {
  semester.courses.push({
    id: semester.courses.length + 1,
    name: '',
    credit: 0,
    markOver100: 0.0,
    grade: '',
  });  
  this.setState(this.state); // trigger re-render
}