簡體   English   中英

將函數作為道具發送給它時,React 組件會重新渲染

[英]React component rerenders when sending function as props to it

我有一個子組件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)}/> 

但是,這些功能一直在重新創建。 我怎樣才能解決這個問題?

當您像這樣發送函數時,您正在創建一個匿名函數,每次父組件渲染時都會重新創建該函數:

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

這是一個匿名函數,它在生活中的全部目的是調用實際的函數startExam 它是在父級的渲染函數中定義的,因此每次都會重新創建。 您也可以直接發送該功能,即

startExam={this.startExam}

在這種情況下,道具現在引用一個穩定的函數,不會每次都重新創建。 我想這會解決你的問題。

但是,我並不完全清楚為什么每次都重新創建該函數並且您的子組件正在重新渲染很重要。 道具不會在無限長的時間內改變,而只會在父級重新渲染時改變。 這通常不是問題,除非您基於其他一些操作來查看之前的 props 是否已更改(例如 lodash, _.isEqual(prevProps,this.props) )。

暫無
暫無

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

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