React(v16.4) コンポーネントライフサイクルメソッドまとめ

#はじめに

Qiita初投稿です。去年からReact、React Nativeでアプリ制作をしてきた中で学んだことを書き留めていきます。React、いろいろな使い方ができて奥が深いところがとても面白いですね。私自身Reactを勉強中で、この記事はReactを勉強中の人に向けて書いています。内容はTypeScript + React前提であることを理解した上でお読みください。

# 0. Reactのコンポーネント

すでに知ってるよ！って方は読み飛ばして大丈夫です。ReactではUIを構成する要素のことをコンポーネント(`Component`)と呼びます。具体的にはボタンやヘッダー、コンテナなどのことです。Reactで開発する利点としてはそれらのUIパーツをそれぞれ細かくコンポーネントに分けておくことで、再描画が必要なものだけに更新を走らせてパフォーマンスをチューニングできる点が挙げられます。

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

![Component Intervals](https://qiita-image-store.s3.amazonaws.com/0/89544/98b60cf7-f928-6dc1-75fe-3a87e00aa29f.png)

Reactのコンポーネントにはライフサイクルがあります。そして[Reactの公式ドキュメント](https://reactjs.org/docs/react-component.html)によると、`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. ライフサイクルメソッド(基本編)

![Important Component Lifecycle Methods ](https://qiita-image-store.s3.amazonaws.com/0/89544/a2141a88-550e-d173-9a6a-0a20989c1051.png)

ここが当記事の本題です。まず、最低限覚えておくべきコンポーネントのライフサイクルメソッドは`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. ライフサイクルメソッド(上級編)

![Advanced Component Lifecycle Methods](https://qiita-image-store.s3.amazonaws.com/0/89544/7a0d64e4-ed30-43c7-1f84-c5cb97fbf4d1.png)

上記の基本のメソッドに加え、必要であれば下記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)](https://medium.com/bananatag-engineering-blog/summary-of-react-component-lifecycle-methods-v16-8-55a4e45f50a5)


# 参考URL
- [React.Component - React](https://reactjs.org/docs/react-component.html)
- [React Component ライフサイクル ひとめぐり](https://iktakahiro.hatenablog.com/entry/2018/05/28/123000)
- [React component ライフサイクル図](https://qiita.com/kawachi/items/092bfc281f88e3a6e456)
- [React Lifecycle Methods- how and when to use them](https://engineering.musefind.com/react-lifecycle-methods-how-and-when-to-use-them-2111a1b692b1)
- [React NativeでStateのライフサイクル処理](https://medium.com/@yurihotate/react-native%E3%81%A7state%E3%81%AE%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB%E5%87%A6%E7%90%86-7509f619d43f)