2021年8月29日日曜日

React:コンポーネントのライフサイクル

1.Reactのコンポーネント

ReactではUIを構成する要素のことをコンポーネント(Component)と呼びます。

具体的にはボタンやヘッダー、コンテナなどのことです。Reactで開発する利点としてはそれらのUIパーツをそれぞれ細かくコンポーネントに分けておくことで、再描画が必要なものだけに更新を走らせてパフォーマンスをチューニングができます。

2.コンポーネントのライフサイクル

ライフサイクルにはまず、大きく分けて3つの期間があります。

それぞれ順に

Mounting、Updating、Unmountingと呼ばれます。

2.1.Mounting

UIにコンポーネントが描画されるまでの準備期間。

使用できるメソッド:

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

2.2.Updating

UIにコンポーネントが表示されていて、基本的にユーザーが操作できる期間。

使用できるメソッド:

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

2.3.Unmounting

他のコンポーネントに切り替える前に現在のコンポーネントを破棄するための期間。

使用できるメソッド:

  • componentWillUnmount()

3.ライフサイクルメソッド(基本編)

3.1.constructor()

Mounting時

JSXおよびTSXのフォーマットではまず見かけません。JavaScriptでReactを書く場合にstateの初期化やactionのバインドのために使用します。


3.2.componentDidMount()

Mounting時

1度目のrenderが呼ばれた後に1度だけ呼ばれるメソッドです。この時点ではまだUIに表示されていません。データをフェッチしたり、アニメーションやタイマーをセットする場合はここで行います。このメソッドからはDOMが作成されていますが、直接のDOM操作などライフサイクルを外れる処理は原則避けましょう。


3.3.render()

Mounting/Updating時

コンポーネントの根幹となる、一番呼ばれるかつ必須のメソッドです。ここに書いてあるコードが実際にUIに現れるものになります。

renderはpropsやstateが更新されるたびに呼ばれるため、ここで直接propsやstateを操作する処理を書いてはいけません。新しい関数を定義するのも避けましょう。そしてAPIのように、propsやstateの値が変わっても結果は冪等であるべきです。

※冪等:べきとうは、大雑把に言って、ある操作を1回行っても複数回行っても結果が同じであることをいう概念です


3.4.componentDidUpdate()

Updating時

第一引数に1つ前のprops、第二引数に1つ前のstate、第三引数にsnapshot(後述のgetSnapshotBeforeUpdateの返り値)が入ってきますが、必要なければ省略可能です。これもよく呼ばれるメソッドなため、パフォーマンスを低下させるpropsやstateを更新する処理は最低限にしましょう。また、if文や後述のshouldComponentUpdateで無駄な処理を避けることができます。


3.5.componentWillUnmount()

Unmounting時

現在のコンポーネントを破棄する直前に呼ばれるメソッドで、アニメーションやタイマーを設定していた場合はここで破棄します。そうしないと新しいコンポーネントのサイクルが始まった後も、その分のメモリが開放されないままになってしまいます。ちなみにもうrenderが呼ばれることはないので、ここでpropsやstateを変更しても意味がありません。

4.ライフサイクルメソッド(上級編)

4.1.getDerivedStateFromProps()

Mounting時

これだけはstaticです。第一引数に次のprops、第二引数に前のstateが入ってきます。propsの値によってstateの値を更新したい場合、propsが更新されてrender()が呼ばれる前にstateの更新が必要かどうかをチェックするメソッドです。更新があれば更新後のstate、なければnullを返します。


4.2.shouldComponentUpdate()

Updating時

第一引数に次のprops、第二引数に次のstateを持っており、前のpropsやstateの値やアドレスと比較し、変更がなければfalseを、あればtrueを返します。falseが返るとこのあとのrender()は呼ばれず再描画は行われません。PureComponentを使うと自動的にこの比較を行ってくれるため、自分で書くケースは稀ですが要のメソッドです。


4.3.getSnapshotBeforeUpdate()

Updating時

このメソッドの返り値はcomponentDidUpdateの第三引数に渡ります。具体例に挙げられているようなスクロール位置など、引き継ぎたい値がある場合に使います。


また上記に上げた以外で、エラーをハンドリングしたい場合はcomponentDidCatch()というメソッドが用意されています。

5.使用しないライフサイクルメソッド

補足として、React v16.2までで使用されていて、現在は使用を控えたほうがいいメソッドもここで上げておきます。古い資料ではこれらの記述がありますが、見かけても読み飛ばしてよいです。


5.1.getDefalutProps()

一度だけ呼ばれ、propsが渡されなかった場合に使う値を指定できます。constructorや、TypeScriptではデフォルト値を指定することで解決可能。


5.2.getInitialState()

Mounting時にまず呼ばれ、描画前にstateを変更するためのメソッド。TypeScriptではstateに初期値を指定できるので特に必要性を感じることはありません。


5.3.componentWillMount()

v16.3以降ではUNSAFE_componentWillMount()に改名されており、v17で完全に削除予定。1回目のrenderが呼ばれる直前に実行されます。


5.4.componentWillUpdate()

v16.3以降ではUNSAFE_componentWillUpdate()になっており、これもv17から削除予定です。使いたいと思ったら代わりにcomponentDidUpdate()やgetSnapshotBeforeUpdate()を使用すべき。


5.5.componentWillReceiveProps()

v16.3以降ではUNSAFE_componentWillReceiveProps()で、v17から削除予定。componentDidUpdate()またはgetDerivedStateFromProps()で代用できます。