はじめに
Qiita初投稿です。去年からReact、React Nativeでアプリ制作をしてきた中で学んだことを書き留めていきます。React、いろいろな使い方ができて奥が深いところがとても面白いですね。私自身Reactを勉強中で、この記事はReactを勉強中の人に向けて書いています。内容はTypeScript + React前提であることを理解した上でお読みください。
0. Reactのコンポーネント
すでに知ってるよ!って方は読み飛ばして大丈夫です。ReactではUIを構成する要素のことをコンポーネント(Component)と呼びます。具体的にはボタンやヘッダー、コンテナなどのことです。Reactで開発する利点としてはそれらのUIパーツをそれぞれ細かくコンポーネントに分けておくことで、再描画が必要なものだけに更新を走らせてパフォーマンスをチューニングできる点が挙げられます。
1. コンポーネントのライフサイクル
Reactのコンポーネントにはライフサイクルがあります。そしてReactの公式ドキュメントによると、React.Componentを拡張したコンポーネントでは、あらかじめ用意されているrender()を始めとしたメソッドをライフサイクル内で使用できると書かれています。効率的なコンポーネントを書くためには、それらのメソッドがライフサイクルのどこで実行されるか理解しておく必要があります。
ライフサイクルにはまず、大きく分けて3つの期間があります。それぞれ順に
Mounting、Updating、Unmountingと呼ばれ、コンポーネントの準備期間、表示期間、破棄期間となっています。
Mounting
UIにコンポーネントが描画されるまでの準備期間。1日に例えると夜明け前まででしょうか。
使用できるメソッド:
constructor()getDerivedStateFromProps()render()componentDidMount()
Updating
UIにコンポーネントが表示されていて、基本的にユーザーが操作できる期間。1日に例えると昼の活動時間帯。
使用できるメソッド:
getDerivedStateFromProps()shouldComponentUpdate()render()getSnapshotBeforeUpdate()componentDidUpdate()
Unmounting
他のコンポーネントに切り替える前に現在のコンポーネントを破棄するための期間。1日に例えると日が暮れた後。
使用できるメソッド:
componentWillUnmount()
Updatingの間はpropsまたはstateの更新をトリガーに何度もサイクルが実行されますが、MountingとUnmountingはそれぞれ始まりと終わりの一度ずつのみ実行されます。
2. ライフサイクルメソッド(基本編)
ここが当記事の本題です。まず、最低限覚えておくべきコンポーネントのライフサイクルメソッドはrenderを含め5つありますが、必須のrender()以外はオプショナルのため、書くことがなければ省略します。
constructor()
Mounting時
JSXおよびTSXのフォーマットではまず見かけません。JavaScriptでReactを書く場合にstateの初期化やactionのバインドのために使用します。
componentDidMount()
Mounting時
1度目のrenderが呼ばれた後に1度だけ呼ばれるメソッドです。この時点ではまだUIに表示されていません。データをフェッチしたり、アニメーションやタイマーをセットする場合はここで行います。このメソッドからはDOMが作成されていますが、直接のDOM操作などライフサイクルを外れる処理は原則避けましょう。
render()
Mounting/Updating時
コンポーネントの根幹となる、一番呼ばれるかつ必須のメソッドです。ここに書いてあるコードが実際にUIに現れるものになります。renderはpropsやstateが更新されるたびに呼ばれるため、ここで直接propsやstateを操作する処理を書いてはいけません。新しい関数を定義するのも避けましょう。そしてAPIのように、propsやstateの値が変わっても結果は冪等であるべきです。
componentDidUpdate()
Updating時
第一引数に1つ前のprops、第二引数に1つ前のstate、第三引数にsnapshot(後述のgetSnapshotBeforeUpdateの返り値)が入ってきますが、必要なければ省略可能です。これもよく呼ばれるメソッドなため、パフォーマンスを低下させるpropsやstateを更新する処理は最低限にしましょう。また、if文や後述のshouldComponentUpdateで無駄な処理を避けることができます。
componentWillUnmount()
Unmounting時
現在のコンポーネントを破棄する直前に呼ばれるメソッドで、アニメーションやタイマーを設定していた場合はここで破棄します。そうしないと新しいコンポーネントのサイクルが始まった後も、その分のメモリが開放されないままになってしまいます。ちなみにもうrenderが呼ばれることはないので、ここでpropsやstateを変更しても意味がありません。
3. ライフサイクルメソッド(上級編)
上記の基本のメソッドに加え、必要であれば下記3つのメソッドが使用できます。使用頻度は高くはありませんが、パフォーマンスのチューニングや高度な操作を行いたいときに使用する重要なメソッドです。ちなみにpropsやstateの更新以外に、forceUpdate()を使って再描画させることもできます。
getDerivedStateFromProps()
Mounting時
これだけはstaticです。第一引数に次のprops、第二引数に前のstateが入ってきます。propsの値によってstateの値を更新したい場合、propsが更新されてrender()が呼ばれる前にstateの更新が必要かどうかをチェックするメソッドです。更新があれば更新後のstate、なければnullを返します。
shouldComponentUpdate()
Updating時
第一引数に次のprops、第二引数に次のstateを持っており、前のpropsやstateの値やアドレスと比較し、変更がなければfalseを、あればtrueを返します。falseが返るとこのあとのrender()は呼ばれず再描画は行われません。PureComponentを使うと自動的にこの比較を行ってくれるため、自分で書くケースは稀ですが要のメソッドです。
getSnapshotBeforeUpdate()
Updating時
このメソッドの返り値はcomponentDidUpdateの第三引数に渡ります。具体例に挙げられているようなスクロール位置など、引き継ぎたい値がある場合に使います。
また上記に上げた以外で、エラーをハンドリングしたい場合はcomponentDidCatch()というメソッドが用意されています。
4. 使用しないライフサイクルメソッド
補足として、React v16.2までで使用されていて、現在は使用を控えたほうがいいメソッドもここで上げておきます。古い資料ではこれらの記述がありますが、見かけても読み飛ばしてよいです。
getDefalutProps()
一度だけ呼ばれ、propsが渡されなかった場合に使う値を指定できます。constructorや、TypeScriptではデフォルト値を指定することで解決可能。
getInitialState()
Mounting時にまず呼ばれ、描画前にstateを変更するためのメソッド。TypeScriptではstateに初期値を指定できるので特に必要性を感じることはありません。
componentWillMount()
v16.3以降ではUNSAFE_componentWillMount()に改名されており、v17で完全に削除予定。1回目のrenderが呼ばれる直前に実行されます。
componentWillUpdate()
v16.3以降ではUNSAFE_componentWillUpdate()になっており、これもv17から削除予定です。使いたいと思ったら代わりにcomponentDidUpdate()やgetSnapshotBeforeUpdate()を使用すべき。
componentWillReceiveProps()
v16.3以降ではUNSAFE_componentWillReceiveProps()で、v17から削除予定。componentDidUpdate()またはgetDerivedStateFromProps()で代用できます。
おわりに
実際にまとめてみると基本的なものはrender以外4つだけでした。メソッド名長いなあ...
追記
加筆修正した英語版を会社のエンジニアリングブログに寄稿しました。
Summary of React Component Lifecycle Methods (v16.8)


