ReactのライフサイクルやPureComponentについて

今回はReactのライフサイクルやPureComponent辺りについて紹介したいと思います。

早速ですが、ライフサイクルはMountingUpdatingUnmountingError Handlingがあります。(今回の記事ではUnmountingとError Handlingについては紹介しません。)

Mounting

reactjs.org

以下のメソッドは、コンポーネントインスタンスを作成してDOMに追加される時に呼び出されます。呼び出される順番は以下の順番です。

  • constructor()
  • static getDerivedStateFromProps()
  • render()
  • componentDidMount()

Updating

reactjs.org

以下のメソッドはコンポーネントが再レンダリングされる時に呼ばれます。

  • static getDerivedStateFromProps()
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate()

ここで重要なのはshouldComponentUpdateです。 コンポーネントがrenderされる前に呼ばれます。 このメソッドは、nextProps, nextStateを受け取り現在のpropsとstateを比較します。更新するときはtrueを更新が必要ない場合はfalseを返します。

注意したいのは、React.Componentの場合はshouldComponentUpdateはデフォルトでtrueを返すということです。 なのでReact.Componentの場合はshouldComponentUpdateでロジックを書く必要があります。

簡単な例

type Props = {
  name: string;
  age: number;
}

class User extends React.Component<Props> {
  shouldComponentUpdate(nextProps:Props) {
    if(this.props.name === nextProps.name) {
      return true
    } else {
      return false
    }
  }
  /* 以下省略 */

例えば親のコンポーネントの状態だけが変更し、子のコンポーネントのpropsやstateに変化がない場合に子のコンポーネントも一緒にマウントされます。そうするとコンポーネントの描画速度が遅くなります。ですのでReact.Componentで書く場合は、ちゃんとshouldComponentUpdateを使って描画パフォーマンスを最適化してあげる必要があります。

React.PureComponent

次に最初の方で挙げたReact.PureComponentについてです。

reactjs.org

結論を先に言うとReact.PureComponentshouldComponentUpdateの処理が実装済みとなっています。ですのでReact.PureComponentを使うのが良いでしょう。ですがここで注意したいのは、React.PureComponentのshouldComponentUpdateはshallow compareするので以下のケースの場合、常にマウントされる結果となります。

class App extends React.PureComponent {
  render() {
    return (
      <div className="App">
        <User families={{ brother: 2, sister: 1 }} name="sato" age={20} />
      </div>
     );
  }
}

propsにはつねに新しいオブジェクトを受け取っています。 shallow compareなのでプロパティと値が正しくてもshouldComponentUpdateの戻り値はtrueを返してしまいます。今はオブジェクトの階層は深くありませんが、もっと階層がある場合などこのような場合などを考慮するとPureComponentの受け取るpropsやstateなどはシンプルなものにすると良いでしょう。また深い階層でpropsやstateの値が変更されるとわかっている場合は、forceUpdate()を使うのも一つの方法です。

Shallow Compareについて

reactjs.org

Pure.Componentがリリースされる前は、Shallow Compareを使用していました。このアドオンがPure.Componentの役割を果たしていました。

以下のように使います。(公式サイトから引用)

// インポートする方法

import shallowCompare from 'react-addons-shallow-compare'; // ES6
var shallowCompare = require('react-addons-shallow-compare'); // ES5 with npm

shallowCompareメソッドには同じようにnextPropsnextStateを渡してあげます。そうすることでshallowCompareが比較してくれます。

export class SampleComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState);
  }

  render() {
    return <div className={this.props.className}>foo</div>;
  }
}

まとめ

Reactのコンポーネントの描画する仕組みを知っておくことで、最適な描画パフォーマンスを実現できると思います。 今回紹介したもの以外にReact.memorecomposeのpureなどがあるので次はこれらについて紹介したいと思います。