コンポーネントのライフサイクル関数

Stencilのコンポーネントには、多数のライフサイクルメソッドがあり、コンポーネントのロード、更新、アンロードのタイミングを知るために使用できます。これらのメソッドをコンポーネントに追加すれば、適切なタイミングで、任意の操作を行えます。

コンポーネントクラス内で、次に紹介するメソッドを使用すると、Stencilはそれらを正しい順序で自動的に呼び出します。

connectedCallback()

コンポーネントがDOMに接続されるたびに、呼び出されます。 コンポーネントが最初に接続されたとき、このメソッドは componentWillLoadの前に呼び出されます。

このメソッドは、DOM内で要素が、attachedまたは、moveされるたびに、複数回呼び出されるので注意してください。

const el = document.createElement('my-cmp');
document.body.appendChild(el);
// connectedCallback() called
// componentWillLoad() called (first time)

el.remove();
// disconnectedCallback()

document.body.appendChild(el);
// connectedCallback() called again, but `componentWillLoad` is not.

これは、このメソッドの素晴らしい使用例です!

この lifecycleフックは、Custom Elements Specで説明されているものと、同じセマンティクスに従います。

disconnectedCallback()

コンポーネントが、DOMから切断されるたびに呼び出されます。つまり、コンポーネントが複数回ディスパッチされる可能性があり、"onDestroy"のイベントと混同しないでください。

この lifecycleフックは、Custom Elements Specで説明されているものと同じセマンティクスに従います。

componentWillLoad()

コンポーネントが、最初にDOMに接続された直後に、1回だけ呼び出されます。 promiseを返すことができ、最初のレンダリングを待つために使用できます。

componentDidLoad()

コンポーネントが完全に読み込まれ、最初の render()が発生した直後に1回呼び出されます。

componentWillRender()

すべての render()の前に呼び出されます。

promiseを返すことができ、今後のレンダリングを待機するために使用できます。

componentDidRender()

すべての render()の後に呼び出されます。

componentWillUpdate()

一部の Prop()または State()が変更されたために、コンポーネントが更新されようとしているときに呼び出されます。 最初の render()の間に呼び出されることはありません。

promiseを返すことができ、次のレンダリングを待つために使用できます。

componentDidUpdate()

コンポーネントが更新された直後に呼び出されます。 最初の render()の間に呼び出されることはありません。

Component initialized componentDidLoad() componentDidUpdate() componentWillUpdate() componentDidUnload() @Watch(‘propName’) Change in a value of prop or state triggers re-render Component removed render() componentWillLoad()

レンダリングの状態

レンダリングされた状態を更新する場合は、常に componentWillLoad() または componentWillUpdate() メソッド内で行うことをお勧めします。また、 componentDidLoad()メソッドや、 componentDidUpdate()メソッドを使用してレンダリングされた状態を更新すると、別の再レンダリングが発生しますが、これはパフォーマンスにとって理想的ではありません。

componentDidUpdate()で状態を更新する必要がある場合、コンポーネントが無限ループに陥る可能性があります。 もし、componentDidUpdate() 内で状態を更新することが避けられないなら、そのメソッドは、propsや状態が"ダーティ"であるかどうか(データが実際に違うのか、以前と同じなのか)を検出する方法を持っていなければいません。ダーティーチェックを行うことで、 componentDidUpdate()は同じデータをレンダリングすることを回避できます。

ライフサイクルヒエラルキー

ライフサイクルメソッドの便利な機能は、子コンポーネントのライフサイクルも考慮に入れていることです。たとえば、親コンポーネントの"cmp-a"に子コンポーネントの"cmp-b"がある場合、"cmp-a"は"cmp-b"のロードが完了するまで"ロードされた"とは見なされません。別の言い方をすれば、最も深いコンポーネントが最初にロードを終えてから、 componentDidLoad()の呼び出しが始まるということです。

また、Stencilがlazy-load componentsを実行できて、非同期レンダリングを持っていても、ライフサイクルメソッドは、正しい順序で呼び出されることに、注意が必要です。つまり、トップレベルのコンポーネントは、すでにロードされてる可能性がありますが、すべてのライフサイクルメソッドは、正しい順序で呼び出されます。これは、子コンポーネントの読み込みが完了するまで待機することを意味します。同じことがまったく逆の場合にも当てはまります。つまり、子コンポーネントはすでに準備されているが、親コンポーネントは準備ができていない場合があります。

以下の例では、コンポーネントの単純な階層構造を示しています。番号付きリストは、ライフサイクルメソッドが起動する順番を示します。

  <cmp-a>
    <cmp-b>
      <cmp-c></cmp-c>
    </cmp-b>
  </cmp-a>
  1. cmp-a - componentWillLoad()
  2. cmp-b - componentWillLoad()
  3. cmp-c - componentWillLoad()
  4. cmp-c - componentDidLoad()
  5. cmp-b - componentDidLoad()
  6. cmp-a - componentDidLoad()

一部のコンポーネントが、既に読み込まれている場合と、読み込まれていない場合でも、コンポーネント階層全体は、その子コンポーネントの読み込みとレンダリングが完了するまで待機します。

非同期ライフサイクルメソッド

ライフサイクル・メソッドはプロミスを返すこともでき、これによってメソッドは非同期的にデータを取得したり、非同期タスクを実行したりすることができます。これの例として、コンポーネントでレンダリングされるデータをフェッチすることが挙げられます。たとえば、あなたが読んでいるこのサイトでは、レンダリングの前にコンテンツデータをフェッチします。しかい、 fetch()は非同期であるため、すべてのコンテンツがレンダリングされるまで、親コンポーネントが"ロード済み"と見なされないようにするには、 componentWillLoad()Promiseを返すことが重要です。

以下の例は、 componentWillLoad()が親コンポーネントに、データの読み込みが完了するのを待つ方法を示す簡単な例です。

componentWillLoad() {
  return fetch('/some-data.json')
    .then(response => response.json())
    .then(data => {
      this.content = data;
    });
}

この簡単な例は、時計を示しており、1秒ごとに現在の時刻を更新します。 componentDidLoadは1回しか呼び出さないので、タイマーのインスタンスは一度しか実行されないことになります。コンポーネントがアンロードされると、タイマーが停止します。

import { Component, State, h } from '@stencil/core';

@Component({
  tag: 'custom-clock'
})
export class CustomClock {

  timer: number;

  @State() time: number = Date.now();

  componentDidLoad() {
    this.timer = window.setInterval(() => {
      this.time = Date.now();
    }, 1000);
  }

  componentDidUnload() {
    window.clearInterval(this.timer);
  }

  render() {
    const time = new Date(this.time).toLocaleTimeString();

    return (
      <span>{ time }</span>
    );
  }
}

以下は実行例です。動作を確認したい場合は、開発ツールで調べてください。 4:05:00 AM

BackNext
Contributors