[Web] constructor vs connectedCallback

hyeondoonge·2024년 2월 28일
1

개요

web-components 공식문서를 보다보면 constructor 또는 connectedCallback에 이벤트를 붙이거나 멤버변수 초기화, attribute 접근 등의 동작을 수행하는 모습을 볼 수 있다.

둘에는 어떤 차이가있는지 명확히 하여 요구사항을 보다 올바르게 구현하기위해, 차이점을 알아보도록하자~

차이점

우선 이 두 함수는 웹 컴포넌트의 생명주기에 관여하는 함수들인데, 가장 중요한 차이점은 어느 시점에 호출되는지이다.

constructor는 new 연산자를 이용해 인스턴스를 생성할 때 호출되는 생성자 함수이다.

connectedCallback은 공식문서에 기재된 내용과 같이, 웹 컴포넌트가 DOM에 연결되었을 때마다 호출된다. 그렇기 때문에, 동일한 대상이 반복해서 DOM에 연결되면 여러 번 호출될 수 있는 함수이다. 하지만, constructor는 단 한번 호출된다.

이러한 차이를 이해하면 어느 시점에 어떤 행동을 수행해야하는지 판단이 설 수 있을 것이다.

웹 컴포넌트를 선언하는 방식은 다양하며, 이에 따라 두 함수들의 호출 시점이 달라질 수 있다.

이게 무슨 말일까? 다양한 사례를 통해 좀 더 깊게 이해해보도록하자. 참고로 하위 코드와 결과들은 chrome 121.0.6167.160 환경에서 실행된 것들이며, 이외의 환경에서는 다른 결과가 나올 수 있다.

case 1. CustomElementRegistry에 정의 후, element 선언

<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'></meta>
    <title></title>
  </head>
	<script>
		customElements.define('edit-area', class extends HTMLElement {
				// ...
		});
	</script>
  <body>
		<edit-area name="수정영역"></edit-area>
  </body>
</html>

동작은 다음과 같다.

  1. script 실행 후 CutsomElementRegistry라고하는, 웹 컴포넌트의 정의를 보유하고 있는 객체에 edit-area에 대한 정보를 저장한다.
  2. body내 edit-area 선언을 파싱하고, edit-area의 생성자 함수를 호출한다.
  3. edit-area의 element 객체가 만들어지고 document에 연결되면 connectedCallback이 호출된다.

⇒ constructor내에서 edit-area의 name attribute에는 접근하지 못하기 때문에 connectedCallback에 접근하도록해야한다.

case 2. element 선언 후, CustomElementRegistry에 정의

<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'></meta>
    <title></title>
  </head>
  <body>
		<edit-area></edit-area>
  </body>
	<script>
		customElements.define('edit-area', class extends HTMLElement {
				// ...
		});
	</script>
</html>
  1. body내 edit-area가 파싱된다. 이에 대응하는 웹 컴포넌트 정의가 없어 무시된다.
  2. edit-area element 객체를 만들고 DOM에 붙인다.
  3. 웹 컴포넌트가 정의된 직후 생성자 함수가 호출된다.

⇒ 해당 요소에 속성, 자식이 이미 등록된 상태여서 constructor내에서 멤버변수에 접근하는 것이 허용된다

case 3. JS로 CustomElementRegistry에 정의, element 선언 분리

webpack으로 js를 번들링하고 html와 연결해서 많이들 사용할 것이다.
아래와 같이 2가지 케이스는 모두 DOM이 다 구축된 후, 로드한 스크립트를 실행하기 시작한다. 이후 CustomElementRegistry에 edit-area를 등록하는 것도 동일.

  • innerHTML를 통해 선언
// html
<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'></meta>
    <title></title>
		<script defer src="main.bundle.js"></script>
  </head>
  <body>
  </body>
</html>

// js
import EditArea from '@_components/editArea/EditArea';

customElements.define('edit-area', EditArea);
document.body.innerHTML = `<edit-area></edit-area>`;
  1. edit-area element가 구축이 된다.
  2. constructor와 connectedCallback이 순차적으로 실행된다.

⇒ element의 attribute나 className등의 attribute들을 조회하거나 수정하는 작업들이 가능하다.

  • createElement를 통해 선언
// html
<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'></meta>
    <title></title>
		<script defer src="main.bundle.js"></script>
  </head>
  <body>
  </body>
</html>

// ts 
import EditArea from '@_components/editArea/EditArea';

customElements.define('edit-area', EditArea);
document.body.append(document.createElement('edit-area'))
  1. createElement 호출 시점에 edit-area의 생성자 함수가 호출된다.
  2. append 호출 후 connectedCallback이 호출된다.

⇒ element의 attribute나 className등의 attribute들을 조회하거나 수정하는 작업들이 불가하다.

결론

이러한 여러 케이스들을 동작시켜보면서 web-components 정의, 선언방식, 위치에 따라 constructor, connectedCallback에서 할 수 있는 행동들이 달라질 수 있다는 것을 알 수 있었다.

특수한 경우에는 constructor내에서 DOM에 접근하고 수정하는 동작들이 항상 가능한 반면 그렇지 않은 경우도 있다.

공식문서에서는 attribute 접근, innerHTML 세팅, 자식 접근 등의 행동들을 constructor보단 connectedCallback 내에서 할 것을 권장한다.

In the class constructor, you can set up initial state and default values, register event listeners and perhaps create a shadow root. At this point, you should not inspect the element's attributes or children, or add new attributes or children. See Requirements for custom element constructors and reactions for the complete set of requirements. - MDN web docs

constructor내에서 수행해도된다는 것이 보장될 수 있는 동작들 같은 경우, ex. 단 한번의 멤버변수 초기화, 리스너 연결, shadowRoot 연결 constructor에서 해도 괜찮은 듯하다.

하지만 외에 element attribute에 접근하고 수정해야되는 동작들을 constructor 내에서 수행하고있다면 잠재적인 버그가 유발될 수 있기 때문에, 권장사항에 따라 connectedCallback을 활용하는 것이 좋겠다.

참고

https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements
https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-conformance

0개의 댓글

관련 채용 정보