向组件发送功能时,React组件重新渲染

时间:2020-03-05 15:29:01

标签: javascript reactjs

我有一个子组件StartExam,在其中我从父组件发送两个作为道具的函数。我看到它一直在重新渲染,因为它一直在获取新的函数值。我已经使用这段代码来找出正在更新的道具,它给了我正在发送的两个功能。

componentDidUpdate(prevProps, prevState, snapshot) {
    Object.entries(this.props).forEach(([key, val]) =>
      prevProps[key] !== val && console.log(`Prop '${key}' changed`)
    );
    if (this.state) {
      Object.entries(this.state).forEach(([key, val]) =>
        prevState[key] !== val && console.log(`State '${key}' changed`)
      );
    }
  }

这是我从父组件发送函数的方式:

         <Route path={`${matchedPath}/start`}
                 render={
                   this.examStatusGuard(
                     'NOT_STARTED',
                     (props) =>
                       <StartExam 
                         language={this.state.language} 
                         startExam={() => this.startExam()}
                         logAction={(action) => this.logAction({action})}/>)
                 }
          />

这是examStatusGuard函数:

  examStatusGuard(requiredState, renderFunc) {
    return (props) => {
      if (this.state.exam.status !== requiredState) {
        return <Redirect to={this.examStatusDefaultUrl()}/>
      }
      return renderFunc(props);
    }
  }

这是我作为道具发送的两个功能:

logAction(actionModel) {
    const wholeActionModel = {
      language: this.state.language,
      taskId: null,
      answerId: null,
      ...actionModel
    };
    console.log(wholeActionModel);
    return wholeActionModel;
  }

startExam() {
    this.logAction({action: actions.EXAM_STARTET});

    this.examGateway.startExam()
      .then(() => this.loadExam())
      .then(() => {
        this.props.history.push("/exam/task/0");
        this.logAction({action: actions.TASK_OPEN, taskId: this.state.exam.tasks[0].id});
      });
  };

我不希望重新创建函数的原因是,在子组件中,我有一个调用logAction的方法,并且该方法一直被调用,而不是一次被调用。 这是方法:

renderFirstPage() { 
  this.props.logAction(actions.INFOSIDE_OPEN); 
  return <FirstPage examInfo={this.props.eksamensInfo}> 
           {this.gotoNextPageComponent()} 
         </FirstPage> 
} 

我尝试发送答案中建议的功能,但将this绑定到它们:

  <StartExam 
      language={this.state.language} 
      startExam={this.startExam.bind(this)}
      logAction={this.logAction.bind(this)}/> 

但是,这些函数一直都在重新创建。 我该如何解决?

1 个答案:

答案 0 :(得分:1)

发送像您一样的函数时,您将创建一个匿名函数,每次父组件呈现时都会重新创建该函数:

startExam={() => this.startExam()}

这是一个匿名函数,其整个生命目的是调用实际函数startExam。它是在父级的render函数中定义的,因此每次都会重新创建。您也可以直接将该函数本身向下发送,即

startExam={this.startExam}

在这种情况下,道具现在引用的稳定函数不会每次都被重新创建。我想这会解决您的问题。

但是,对于我来说尚不十分清楚,为什么每次都重新创建函数并且重新渲染子组件很重要。道具不会改变无限的时间,而是仅在父项重新渲染时才改变。通常这不是问题,除非您采取其他措施来查看先前的道具是否已更改(例如lodash,_.isEqual(prevProps,this.props))。