ライフサイクルフック
フックメソッドを提供することで、コンポーネントのライフサイクル内で特定のイベントが発生したときの挙動を定義できます。
実際に動く様子はこちら: ライフサイクルの順序デモ ↗は各フックが発火するたびにログを出力し、属性のライフサイクルデモ ↗は属性の変更がどのようにそれらを駆動するかを示します。
onInit()
Section titled “onInit()”- コンポーネントがDOMに接続されたときにトリガーされます
- コンポーネントのセットアップに最適です
import { WebComponent } from 'https://esm.sh/web-component-base@latest'
class ClickableText extends WebComponent { // コンポーネントがHTMLドキュメント内で使われたときに呼び出される onInit() { this.onclick = () => console.log('>>> click!') }
get template() { return `<span style="cursor:pointer">Click me!</span>` }}afterViewInit()
Section titled “afterViewInit()”- ビューが最初に初期化された後にトリガーされます
class ClickableText extends WebComponent { // コンポーネントのinnerHTMLが最初に埋められたときに呼び出される afterViewInit() { const footer = this.querySelector('footer') // ビューが初期化された後、footerに対して何か処理を行う }
get template() { return `<footer>Awesome site © 2023</footer>` }}onDestroy()
Section titled “onDestroy()”- コンポーネントがDOMから切断されたときにトリガーされます
onInit()で行ったセットアップを元に戻すのに最適です
import { WebComponent } from 'https://esm.sh/web-component-base@latest'
class ClickableText extends WebComponent { clickCallback() { console.log('>>> click!') }
onInit() { this.onclick = this.clickCallback }
onDestroy() { console.log('>>> removing event listener') this.removeEventListener('click', this.clickCallback) }
get template() { return `<span style="cursor:pointer">Click me!</span>` }}onChanges()
Section titled “onChanges()”- attribute値が変更されたときにトリガーされます
changesオブジェクトはpropertyとattributeをきれいに分離します。property:propsへのアクセス方法に一致するcamelCaseのpropキー(例:myName)attribute: 変更されたkebab-caseのattribute名(例:my-name)previousValue/currentValue: 変更前と変更後の値
props から直接値を読み取るには property を使い(this.props[property])、生のattribute名が必要なときは attribute を使ってください。
実際に動く様子はこちら: onChangesのペイロードデモ ↗
import { WebComponent } from 'https://esm.sh/web-component-base@latest'
class ClickableText extends WebComponent { // attribute値が変更されたときに呼び出される onChanges(changes) { const { property, attribute, previousValue, currentValue } = changes console.log('>>> ', { property, attribute, previousValue, currentValue }) }
get template() { return `<span style="cursor:pointer">Click me!</span>` }}アップグレードの順序とバッファリングの保証
Section titled “アップグレードの順序とバッファリングの保証”Custom Elements仕様によると、マークアップにすでにattributeが存在する状態(例: <my-el my-name="Zoe">)で要素がアップグレードされるとき、ブラウザは attributeChangedCallback を connectedCallback より前に発火します。文字どおりに受け取ると、これは render() と onChanges() が onInit() より前に実行される可能性があることを意味し、そのため onInit で行うセットアップ(イベントの配線、外部状態の読み取りなど)は、最初のレンダリングの時点ではまだ行われていないことになります。happy-dom/jsdomのようなテスト環境はこの順序を再現しないため、コンポーネントはテストでは通過しても、実際のブラウザでは誤動作することがあります。
WebComponent はこの落とし穴を取り除きます。要素が接続される前に届くattributeの変更はバッファリングされます。
- prop値は即座に適用されるため、
onInit()の内部ですでにthis.propsは正しい状態になっています。 render()とonChanges()の副作用は延期され、onInit()が実行された後に行われます。
接続時、順序は常に次のとおりです。
onInit():this.propsはすでにマークアップで指定されたattributeを反映済み- 単一の
render(): バッファリングされたすべてのpropを一度に反映する afterViewInit()
onChanges() は onInit() より前に発火することは決してありません。 接続前のattribute変更は onChanges() を通して再生されることはありません。最初の render() がすでにそれらを反映しているため、onChanges() は接続後の正真正銘の変更のためだけに予約されています。要素が接続された後は、attributeの変更は通常どおりに振る舞います。各変更が即座に render() と onChanges() をトリガーします。