Reactディープシリーズ4:コンポーネントのライフサイクル


文:徐超、『React進級の道』作者
配布を許可し、転載するには作者と出典を明記してください.

Reactディープシリーズ4:コンポーネントのライフサイクル


Reactはシリーズに深く入り込み、Reactの重点概念、特性、モデルなどを深く説明し、Reactに対する理解を深め、プロジェクトでReactをより柔軟に使用することを目的としています.
コンポーネントはReactアプリケーションを構築する基本単位であり、コンポーネントは、コンポーネントの異なるライフサイクルメソッドに依存するデータ取得、ビジネスロジック処理、およびUIプレゼンテーションの能力を備えなければならない.コンポーネントのライフサイクルは、マウント・フェーズ、更新フェーズ、アンロード・フェーズの3つのフェーズに分けられ、各フェーズには対応するライフサイクル・メソッドが含まれます.一連の文章に深く入り込んでいるため、本稿ではライフサイクルごとの方法の使用について詳しく説明するのではなく、コンポーネントのライフサイクルを使用する際によく遭遇する疑問や誤った使用方法について重点的に説明します.

サーバデータ要求


初心者がReactを使用する場合、コンポーネントに必要なデータを取得するためにサーバにリクエストを送信するタイミングが分からないことがよくあります.コンポーネントに必要な初期データについては,componentDidMountメソッドでデータ要求を行い,このときコンポーネントがマウントを完了し,その代表するDOMがページのDOMツリーにマウントされており,取得したデータが直接DOMノードを操作する必要があったとしても,この場合は絶対に安全である.constructorやcomponentWillMountでは、データ要求を行うことに慣れている人もいますが、componentDidMountの実行時間に比べて、事前の時間はあまりにもわずかです.また、サーバレンダリングを行う場合(SSR)、componentWillMountは2回呼び出され、1回はサーバ側で、1回はクライアント側で、この場合、追加のリクエストが発生します.
コンポーネントがデータ要求を行う別のシーン:親コンポーネントの更新によってコンポーネントのpropsが変化し、コンポーネントのデータ要求がpropsに依存している場合、コンポーネントはデータ要求を再実行する必要があります.例えば、ニュース詳細コンポーネントNewsDetailは、ニュース詳細データを取得する際に、ニュースのidをパラメータとしてサーバ側に渡す必要があり、NewsDetailがすでにマウント状態にある場合、他のニュースをクリックすると、NewsDetailのcomponentDidMountは再呼び出されず、componentDidMountでニュース詳細データ要求を行う方法も再実行されない.この場合、componentWillReceivePropsで、データ要求を行うべきです.
componentWillReceiveProps(nextProps) {
  if(this.props.newId !== nextProps.newsId) {
    fetchNewsDetailById(nextProps.newsId)  //        id,        
  }
}

データ要求を行うタイミングがページ上のインタラクション動作によってトリガーされる場合、例えば、クエリーボタンをクリックした後、データをクエリーする場合、クエリーボタンのイベントリスニング関数でデータ要求を実行するだけでよい場合、一般的には疑問はありません.

フェーズメソッドの呼び出しの更新


コンポーネントの更新は、コンポーネントのライフサイクルで最も複雑なフェーズであり、最大のライフサイクルメソッドに関連するフェーズでもあります.
通常、コンポーネントが更新されると、コンポーネントのライフサイクルメソッドの呼び出し順序は次のとおりです.
componentWillReceiveProps -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate

//       props(props              )->                ->        DOM     ->            DOM ->   DOM     DOM     DOM  

親コンポーネントが更新されるか、コンポーネント自体がsetStateを呼び出すと、コンポーネントが更新されます.親コンポーネントの更新によるコンポーネントの更新、ライフサイクルメソッドの呼び出しについては前述したとおりです.コンポーネント自体がsetStateを呼び出した場合、そのコンポーネントが更新された場合、そのライフサイクルメソッドの呼び出しは次のようになります.
shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate

この場合、componentWillReceivePropsは呼び出されません.
コンポーネントのshouldComponentUpdateがfalseに戻ると、コンポーネントは更新プロセスを停止します.ライフサイクルメソッドの呼び出し順序は次のとおりです.
componentWillReceiveProps -> shouldComponentUpdate ->   

または(コンポーネント自体がsetStateを呼び出し、コンポーネントが更新されます):
shouldComponentUpdate ->   

setStateのタイミング


コンポーネントのライフサイクルメソッドは多く、setStateを呼び出してコンポーネントステータスを更新できるメソッドはどれですか?どのような方法ではいけませんか?
  • で可能な方法componentWillMount、componentDidMount、componentWillReceiveProps、componentDidUpdateここにはいくつかの注意点があります.
  • componentWillMountでsetStateを同期して呼び出すと、コンポーネントが追加のレンダリングを行うことはありません.コンポーネントが経験するライフサイクルメソッドは、componentWillMount->render->componentDidMountの順です.コンポーネントはcomponentWillMountのsetState呼び出しによって再更新操作を実行することはありません.非同期呼び出しsetStateの場合、コンポーネントは追加の更新操作を行います.しかし、実際のシーンではcomponentWillMountでsetStateを呼び出すことはめったにありません.一般的にはconstructorでstateを直接定義することで代用できます.
  • 一般的に、setStateが呼び出されると、コンポーネントは更新プロセスを1回実行し、componentWillReceivePropsなどの更新フェーズのメソッドは再び呼び出されるが、componentWillReceivePropsでsetStateが呼び出されると、新たな更新パスが追加されることはない.すなわち、現在の更新プロセスが終了すると、componentWillReceivePropsなどの更新フェーズのメソッドは二度と呼び出されない.(なお、ここでは同期呼び出しsetStateを指し、非同期呼び出しの場合、コンポーネントが再びレンダリングされる)
  • componentDidUpdateでsetStateを呼び出すには特に注意してください.setStateの前に条件判断が必要です.対応する条件を満たしてこそsetStateになります.グループコンポーネントは更新プロセスを継続して実行し、デッドサイクルに入ります.setStateは新しいコンポーネントの更新をもたらすため、コンポーネントの更新が完了するとcomponentDidUpdateが呼び出され、setStateが続行され、デッドループが発生します.

  • ではできないメソッド他のライフサイクルメソッドはsetStateを呼び出すことができません.主な理由は2つあります.
  • はデッドサイクルを生成する.たとえば、shouldComponentUpdate、componentWillUpdate、renderでsetStateを呼び出すと、コンポーネントの今回の更新はまだ実行されていません.また、新しい更新に入り、更新を繰り返し、デッドサイクルに入ります.
  • は意味がありません.componentWillUnmountが呼び出されると、コンポーネントがアンインストールされます.setStateはコンポーネントを更新するためです.アンインストールするコンポーネントでstateを更新するのは明らかに意味がありません.実際、componentWillUnmountでsetStateを呼び出すと異常が放出されます.


  • render回数!=ブラウザインタフェースの更新回数


    まず次の例を見てみましょう.
    class App extends React.Component {
    
      constructor(props) {
        super(props)
        this.state = {
          bgColor: "red"
        }
      }
    
      render() {
        var {bgColor} = this.state
        return (
          
    Test
    ); } componentDidMount() { this.setState({ bgColor: "yellow" }) } }

    ブラウザでレンダリングされたページを観察すると、ページのTestがあるdivの背景色は、まず赤を表示してから黄色になりますか?それともそのまま黄色に表示されますか?
    答えは:直接黄色に表示されます!
    このプロセスでは、コンポーネントのライフサイクルメソッドが呼び出される順序は次のとおりです.
    constructor -> componentWillMount -> render -> componentDidMount -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate

    コンポーネントはマウントが完了すると、setStateの呼び出しにより、すぐに更新プロセスが実行されます.renderメソッドは2回呼び出されたが,ブラウザインタフェースが2回更新されるわけではないが,実際には2回のDOMの変更が1回のブラウザインタフェースの更新に統合される.React公式サイトでcomponentDidMountの方法を紹介する際にも以下の説明があります.
    Calling setState() in this method will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state.
    これは、コンポーネントrenderの回数がブラウザインタフェースの更新回数に等しいとは限らないことを示しています.JSの実行とDOMのレンダリングはそれぞれブラウザの異なるスレッドで行われるが、JSの実行はDOMのレンダリングをブロックし、上の2回のrenderは1つのJSイベントサイクルで実行されるため、2回のrenderが終了するまでブラウザはインタフェースを更新しない.

    次の予告:


    Reactディープシリーズ5:イベント処理
    新刊書おすすめ『React進級の道』
    著者:徐超
    浙江大学、修士、ベテランの先端エンジニアを卒業し、長期にわたってエネルギー物ネットワーク会社の遠景知能に就職した.8年のソフトウェア開発経験、大フロントエンド技術を熟知し、豊富なWebフロントエンドとモバイルエンド開発経験を持ち、特にReact技術スタックとモバイルHybrid開発技術に対して深い理解と実践経験がある.
    美団評価広告プラットフォーム大フロントエンドチームは20192020年フロントエンド実習生を募集する(偏動効方向)
    有意者メール:[email protected]