Salesforce LWCのライフサイクルまとめ

# これは何？
この記事は「[24日後に立派なSalesforceエンジニアになるWEBエンジニア Advent Calendar 2022](https://qiita.com/advent-calendar/2022/kakakaori)」の12日目の記事です。13日後に立派なSalesforceエンジニアになるために今日からはLightning Web Component (LWC)のライフサイクルについてみていきたいと思います。すごくシンプルだけど実装する上では知っておくと便利なので記事としてまとめておきます。

# LWCのライフサイクル
| ライフサイクル名 | いつ呼ばれるか |
|:-|:-|
|  constructor() | コンポーネントの作成時  |
|  connectedCallback() |  要素がドキュメントに挿入されるとき |
|  renderedCallback() | コンポーネントを表示するとき  |
|  disconnectedCallback() | 要素が削除されたとき  |
|  errorCallback() |  下位コンポーネントでエラーが起きたとき |

## constructor
コンポーネントインスタンスが作成されたタイミングで呼ばれる。

LWCでは`classList`にaddすることでDOMを直接操作してスタイルを制御することもできるが、`constructor`の時点ではまだDOMが用意されていない。そのため`constructor`のタイミング以外で処理を行う必要がある。

```javascript:test.js
import { LightningElement } from 'lwc';
export default class Deprecated extends LightningElement {
    constructor() {
        super();
        // これはダメ
        this.classList.add('new-class');
    }

    connectedCallback() {
        // constructor以外のライフサイクル内での呼び出しであればOK
        this.classList.add('new-class');
    }
}
```

## connectedCallback
要素がドキュメントに挿入されるときに呼ばれる。標準的な初期化処理は`connectedCallback`内で行われることが多い。

## renderedCallback
コンポーネントを表示するタイミングで呼ばれる。コンポーネントがレンダリングされるたびに呼ばれるため、初回呼び出し時のみ処理を行いたいときは`hasRendered`のようなbool値を使い制御を行う必要がある。

## 親子階層のコンポーネントの場合
親子階層のコンポーネントを初期表示するときの呼び出し順については

親：constructor()
親：connectedCallback()
子：constructor()
子：connectedCallback()
子：renderedCallback()
親：renderedCallback()
になる。

### 試してみる

```javascript:parent.js
import { LightningElement } from 'lwc';

export default class Parent extends LightningElement {
    constructor() {
        super();
        console.log('parent-constructor');
    }

    connectedCallback() {
        console.log('parent-connectedCallback');
    }

    renderedCallback() {
        console.log('parent-renderedCallback');
    }
}
```

```html:parent.html
<template>
    <c-child></c-child> 
</template>
```

```javascript:child.js
import { LightningElement } from 'lwc';

export default class Child extends LightningElement {
    
    constructor() {
        super();
        console.log('child-constructor');
    }

    connectedCallback() {
        console.log('child-connectedCallback');
    }

    renderedCallback() {
        console.log('child-renderedCallback');
    }
}
```

### 結果
![スクリーンショット 2022-12-06 22.26.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/74796148-9632-93ee-1ff4-1babc5b3c83b.png)
呼び出される順番が確認できた！


## disconnectedCallback
要素が削除された時に呼ばれる。親子関係にないコンポーネント間での値渡しに使われる`Subscriber`内でこのイベントを呼んでいるのを見かける。

## errorCallback
下位コンポーネントでエラーが起きたときに呼ばれる。

### 試してみる

```javascript:parent.js
import { LightningElement } from 'lwc';

export default class Parent extends LightningElement {
    errorCallback(error, stack){
        throw error;
    }
}
```
```javascript:child.js
import { LightningElement } from 'lwc';

export default class Child extends LightningElement { 
    connectedCallback() {
       throw new Error('Whoops!');
    }
}
```

### 結果
![スクリーンショット 2022-12-06 22.41.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/d258445e-9a18-1d0b-8ec6-fca0e379919a.png)

# 最後に
今日はLWCのライフサイクルについてみていきました。
[ライフサイクルフック](https://developer.salesforce.com/docs/component-library/documentation/ja-jp/lwc/lwc.reference_lifecycle_hooks)に関しては公式にも色々書かれているので興味がある方はぜひご覧ください。（知らなくても実装面ではそこまで困らなさそうだと感じたので一旦は省略しちゃう！）
明日は実際にLWCでコンポーネントを作っていこうと思います。