웹 컴포넌트: 오해를 풀고 진짜 능력 살펴보기
웹 컴포넌트는 종종 속성을 통해서만 문자열 속성 전달이 가능하다는 이유로 비판받습니다. 이 오해는 attributeChangedCallback 메커니즘에 대한 잘못된 이해에서 비롯됩니다. HTML 속성은 마크업의 정적인 부분이며, JS 런타임과 직접 연결되지 않습니다. 객체, 배열 또는 기본형을 전달하려면 컴포넌트 클래스의 게터/세터를 사용하세요. 브라우저는 DOM API나 프록시를 통해 모든 유형의 속성을 직접 설정할 수 있습니다.
class MyElement extends HTMLElement {
set data(value) {
this._data = value;
this.render();
}
}
섀도우 DOM은 스타일과 DOM 격리를 제공하여 외부 충돌로부터 보호합니다. 격리를 단점으로 비판하는 것은 선택을 무시하는 것입니다: 커스텀 엘리먼트는 섀도우 DOM 없이도 작동합니다. 커스터마이징을 위해서는 CSS 변수와 ::part()를 사용하세요:
my-component::part(button) {
background: var(--accent-color);
}
스타일 중복에 대한 오해: Adopted Style Sheets를 사용하면 모든 섀도우 DOM 인스턴스에 공유 스타일을 적용할 수 있습니다.
라이프사이클은 DOM에 연결될 때가 아닌 생성자에서 시작됩니다. 컴포넌트는 메모리에 생성되며, 렌더링 없이 가상화를 위해 DocumentFragment를 통해 조작됩니다.
반은 진실: 레지스트리와 라이프사이클 훅
전역 커스텀 엘리먼트 레지스트리는 고유한 이름을 요구합니다. 해결책은 접두사(예: app-button)와 등록 시 try/catch입니다:
try {
customElements.define('app-button', ButtonElement);
} catch (e) {
console.warn('이름 충돌:', e);
}
충돌은 테스트에서 발견됩니다. 평면 네임스페이스는 JS, DNS, HTML에서 표준 패턴입니다.
connectedCallback/disconnectedCallback 훅은 DOM 내 이동 시 트리거됩니다. 해결책은 초기화 플래그입니다:
connectedCallback() {
if (this._initialized) return;
this._initialized = true;
this.init();
}
등록 해제는 불가능하지만, 이는 장점입니다: 브라우저는 오버헤드 없이 생성자를 캐시합니다.
실제 세부 사항과 해결책
HTML 파싱은 콘텐츠 처리 전에 여는 태그에서 connectedCallback을 트리거합니다. DOM API는 사용할 수 없습니다. 지연 초기화를 위해 defer 또는 type="module"을 사용하세요. 대안은 customElements.whenDefined()입니다:
const button = document.querySelector('app-button');
await customElements.whenDefined('app-button');
button.method();
자식 엘리먼트에 대한 접근을 보장하려면 renderCallback 또는 유사한 훅을 사용하세요.
웹 컴포넌트의 강점
웹 컴포넌트는 기본적으로 HTML 마크업과 JS를 연결합니다. 커스텀 태그는 벤더 종속 없이 서버나 클라이언트에서 통합을 위한 마커 역할을 합니다.
원자적 라이프사이클 관리: 브라우저는 프레임워크와 독립적으로 연결/해제에 대해 알립니다.
Lit, Symbiote.js, 마이크로 프론트엔드를 위한 기초 모델입니다. React, Vue, Angular, SPA, SSR과 함께 작동합니다.
- 오버헤드 없는 격리: 섀도우 DOM은 선택 사항입니다.
- 네이티브 반응성: 속성 + 프록시.
- 다용도성: 위젯부터 WebSocket과 그래픽을 사용한 대시보드까지.
- 가상화: 10만 개 이상의 엘리먼트 목록을 위한 DocumentFragment.
- 스타일링: CSS 변수, ::part(), Adopted Style Sheets.
핵심 요약
- 모든 유형의 속성은 게터/세터를 통해 전달됩니다; 속성은 문자열만을 위한 것입니다.
- 섀도우 DOM은 격리하지만 필요 시 비활성화할 수 있습니다; 변수와 ::part를 통한 스타일.
- 전역 레지스트리는 접두사와 테스트로 해결됩니다; 충돌은 드뭅니다.
connected/disconnected훅과 플래그로 중복 초기화를 방지합니다.- 파싱 비동기성은 defer/module 또는 whenDefined로 해결됩니다.
— Editorial Team
아직 댓글이 없습니다.