template vs render()
このメンタルモデルは、コンポーネントを作成する際の認知的な複雑さを減らすことを目指しています。
templateは読み取り専用のプロパティ(getキーワードで初期化される)で、コンポーネントのビューが_どのように_レンダリングされるかを表します。- ビューのレンダリングを引き起こす
render()メソッドがあります。 - この
render()メソッドは、属性値が変更されるたびに、内部で_自動的に_呼び出されます。 - 必要であれば、任意のタイミングでこの
render()メソッドを_任意で_呼び出し、レンダリングを引き起こすこともできます(例えば、手動でレンダリングをトリガーする必要のある、観測対象外のprivateプロパティがある場合など)。 - カスタムの
templateを扱うためにrender()関数をオーバーライドすることも可能です。lit-htmlを使った例はこちらです: CodePenで見る ↗
実際に動く様子はこちら: テンプレート化デモ ↗は2種類のテンプレートを示し、レンダリング調整デモ ↗はインプレースの再レンダリングが何を保持するか(フォーカス、キャレット位置、未確定の入力値がすべて保持されます)を示します。
コンポーネントの合成
Section titled “コンポーネントの合成”コンポーネントの template は、他のコンポーネントを好きなだけ深くネストして含めることができます。
class CounterBoard extends WebComponent { static props = { title: 'Board' } get template() { return html` <h3>${this.props.title}</h3> <counter-row name="alpha"></counter-row> <counter-row name="bravo"></counter-row> ` }}ネストされた各コンポーネントは、自身がレンダリングするDOMを自分で所有します。外側のコンポーネントが再レンダリングされるとき、reconcilerはネストされた要素に渡すpropをパッチします(これが親から子へデータが流れる仕組みです)が、その要素自身の子は決して触れません。そのため、ネストされたコンポーネントは、祖先が無関係な理由で再レンダリングされても、自身のレンダリング内容や内部状態を保持し続けます。データはattributeとして下方向に流れるため、ネストされたコンポーネントがattributeから読み戻せる値(プリミティブ、あるいはJSONラウンドトリップを生き延びるオブジェクト/配列)を渡すようにしてください。実際に動く様子はこちら: ネストされた合成デモ ↗。
唯一の例外はslotプロジェクションです。shadow-DOMコンポーネントのタグの_内側_に書く子要素はあなたのコンテンツであり、そのコンポーネントの <slot> に投影されるため、親が引き続きそれらを調整し続けます。対照的に、light-DOMコンポーネントは自身の子要素の上にレンダリングするため、投影された子要素としてではなく、attribute経由でデータを渡すようにしてください。