【React入門⑧】コンポーネントのライフサイクルを理解する

f:id:nekorokkekun:20190905094855p:plain:w1000
こちらの記事は、React入門チュートリアルです。

Reactが初めての私がReactを実装していく流れとなるため、初心者の方のつまずきやすいポイントを一通りフォローアップできる内容となっています。

ライフサイクルとは?

ライフサイクルとは、コンポーネントが描画され、イベントなどで値が変更されて再描画され…といったコンポーネントの描画までの「生まれてから死ぬまで(ライフサイクル)」として表したものです。

ライフサイクルを表現するためにはいくつかのメソッドが存在しますが、
以前のチュートリアルで扱っていた

  • constructor
  • render

もライフサイクルメソッドです。

ライフサイクルメソッドの分類

f:id:nekorokkekun:20190905081618p:plain
https://medium.com/@saharshgoyal/react-16-new-life-cycle-methods-inside-out-fdd269c43ccd
ライフサイクルメソッドは3種類に分類することができます。

さらに詳しくライフサイクルメソッドを具体的に見ていきます。

componentWillMount

コンポーネントが描画される直前に実行される。初期化処理などに利用されています。
もしこのメソッドの中でsetStateをした場合、更新後の処理が描画されることになります。

ただしこちらのメソッドはReact v17.0で廃止予定です!(2019/9月時点で最新版は16.9)

componentDidMount

コンポーネントの初回の描画が行われた際に発動するライフサイクルメソッド。
すでにDOMが描画されているため、他のDOMに対するアクセスも可能となっています。

componentWiilReceiveProps

コンポーネントがPropsから値を渡された際に発動するライフサイクルメソッド。
Propsが値を渡すごとに更新されます。

shouldComponentUpdate

StateやPropsのデータが更新されているかどうかを検証し、更新されていれば再描画が行われるライフサイクルメソッド。

StateやPropsが更新されていればtrue、されていなければfalseを返します。

componentWillUpdate

コンポーネントが再描画される(PropsやStateの値が変わる)直前に発動するライフサイクルメソッド。最初の描画時に呼び出されないところが、componentWiilReceivePropsとの違いでしょう。

componentDidUpdate

コンポーネントが再描画された後に発動するライフサイクルメソッド。こちらも最初の描画時には呼び出されません。

componentWillUnmount

コンポーネントがDOMから削除される直前に発動するライフサイクルメソッド。
後にご紹介するsetIntervalメソッドに対するclearIntervalメソッドの配置場所などでよく使われます。

getDerivedStateFromProps

インスタンス化された後に、引数として渡されたPropsやStateを受け取ることができるライフサイクルメソッド。

ライフサイクルメソッドを使ってみる

早速ライフサイクルメソッドを使用してみましょう!

componentDidMountを使った例

import React, {Component} from 'react';
import ReactDOM from 'react-dom';

class App extends Component {
  constructor(props) {
    super(props);
 // stateのtitleに空文字を渡す
    this.state = {title:''};
  }
// コンポーネントが描画された際にstateのtitleに文字列を渡す
  componentDidMount() {
    this.setState({title:'Laravelとねころっけくん5.8'})
  }

  render() {
    return (
      <div>
        <h2>{this.state.title}</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

export default App;

このようなコードを記述すると、componentDidMountで渡した文字列が描画されていることがわかります。componentDidMountはコンポーネントが描画された直後に発動するライフサイクルメソッドでしたね。

ライフサイクルメソッドを複数使用したコンポーネント

React公式から拝借したライフサイクルメソッドを複数使用したコンポーネントを見てみましょう。

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));

serviceWorker.unregister();

src/App.js

import React, {Component} from 'react';
import ReactDOM from 'react-dom';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

export default App;

これで以下のようなコンポーネントの動きになります。
f:id:nekorokkekun:20190905090032g:plain

App.jsのライフサイクルがどのように動いているのか見ていきましょう。

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

まずindex.htmlのrootがついたdiv要素にrenderメソッドでが描画されるように指示されます。

  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

が描画されるとconstructorが動き、stateに現在時刻を渡して初期化。

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

コンポーネントがマウントされたら、1000ミリ秒(1秒)後にtickメソッドを発火させるように指示が出されます。

  tick() {
    this.setState({
      date: new Date()
    });
  }

tickメソッドはstateに新しい時間を設定するためのメソッドです。

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

1000ミリ秒(1秒)後にtickメソッドが発火し、コンポーネントがアンマウントされると走っていたsetIntervalを消します。(これはJavascriptお約束のセットです)


基本的にはcomponentDidMountとcomponentWillUnmountの繰り返しによって、タイマーが作動しているように見えています。