はじめに
WebComponents を使った実装の際に、 connectedCallback()
内で querySelector()
がnullになることがあったので、今回はその理由について解説していきます。
理由
さっそくですが結論から、
connectedCallback()
の実行時には、まだDOM解析が完全に終わっていないからです。
解説
例えば <fr-sample-item>
のslot内に、 <fr-sample-item>
を入れた時に動作が変わるように実装したとします。
実行(Connect)前
実行(Connect)後 ※理想
実行(Connect)後 ※実際
💡
少し見づらいので、分かりやすくしたコードを記載します。
検証環境を用意したので、こちらで動作を確認してみてください。
「ネスト有り」が入った <detail>
が表示されない事が、確認出来るかと思います。
検証環境(slotが空)
何故このような動作になるのか?
まだDOMが解析されていないため、実行時にslotの中身( innerHTML
等)が空になってしまいます。
例えば、二つ目の <fr-sample-item>
の connectedCallback()
の実行時でのDOM解析状況は以下の通りです。
実行時には、slot内のコードまで解析されていません。 そのため、サンプルコードの this.querySelector('fr-sample-item')
が必ずnullになってしまうのが原因です。
ただし、コードの読み込みをパーサーブロッキングしていない場合は起こりません。(パーサーブロッキングした方が良いです。後述します。)
検証環境を用意したので、こちらで動作を確認してみてください。
検証環境(defer属性付与)
なお JavaScript の読み込み時にdefer属性を追加している以外に、変更点はありません。
解決方法
ですが、WebComponentsの読み込みはパーサーブロッキングをした方が良いです。
そこでやや面倒ですが、もう一つcustomElementを定義して使えば解決します。
まとめ
WebComponents での実装には多くの落とし穴があり、一筋縄では実装が出来ません。
落とし穴を回避出来るような情報を、当ブログでなるべく貢献が出来ればと思います。
参考
https://stackoverflow.com/questions/63072769/how-to-use-queryselector-of-tags-inside-a-web-component