MutationObserver를 여러 번 설정하면 같은 요소에 중복 옵저버가 등록될 수 있다. 전역 Set이나 Map으로 관리하는 방법도 있지만, dataset에 관찰 완료 플래그를 기록하는 방법은 가볍고 이식성이 높다.
코드
const OBSERVE_ID_KEY = 'observeId'
const isElementObserved = <T extends HTMLElement = HTMLElement>( ele: T) => Object.hasOwn(ele.dataset, OBSERVE_ID_KEY)
const setObserverId = (id: string) => <T extends HTMLElement = HTMLElement>(ele: T): T => { ele.dataset[OBSERVE_ID_KEY] = id return ele }
export const observeElement = ( observeId: string, element: HTMLElement | string, observerCallback: MutationCallback, options: MutationObserverInit = { childList: true }) => { const observedElement = element instanceof HTMLElement ? element : document.querySelector<HTMLElement>(element) if (observedElement && !isElementObserved(observedElement)) { const observer = new MutationObserver(observerCallback) observer.observe(observedElement, options) setObserverId(observeId)(observedElement) return observer }}사용 예시
// 셀렉터 문자열 또는 HTMLElement 모두 전달 가능observeElement( 'my-list-observer', '#item-list', (mutations) => { for (const mutation of mutations) { console.log('변경 감지:', mutation.type) } })
// 같은 요소에 다시 호출해도 중복 등록되지 않음observeElement('my-list-observer', '#item-list', callback)동작 원리
Object.hasOwn(ele.dataset, OBSERVE_ID_KEY)로data-observe-id속성 존재 여부 확인- 미등록 상태인 경우에만
MutationObserver를 생성하고observe()를 호출 - 관찰 시작 후
ele.dataset[OBSERVE_ID_KEY] = id로 플래그 기록 - 이후 호출에서는
isElementObserved가true를 반환하여 아무 작업도 하지 않음
dataset 값은 HTML의 data-* 속성에 직접 기록되므로 DevTools에서 확인할 수 있다.
장점
- 전역 레지스트리 불필요: 상태를 요소 자체에 저장하므로 별도의
Map이나Set관리가 필요 없음 - 높은 이식성: 프레임워크 의존성 없음, 모든 환경에서 동작
- 디버깅 편의성: DevTools에서 속성 값을 직접 확인 가능
주의사항
요소가 DOM에서 제거되면 dataset 정보도 함께 사라진다. 같은 요소가 재삽입되면 다시 옵저버가 등록된다. 또한 옵저버를 중지하려면 observer.disconnect()를 별도로 호출해야 한다.
hsb.horse