#はじめに
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)