JavaScript의 customElements에서 Proxy을 활용한 객체 변화 감지
앞서 작성한 글을 완벽하게 숙지하고 사용하시다 보면 attribute 값을 업데이트 하는 과정에서 여러 의문이 들 것입니다.
??? : observedAttributes()
와 attributeChangedCallback()
으로 태그의 attribute 값이 바뀌는 것을 감지해주는건 알겠는데…
??? : 여기에 render()
함수를 걸어두면 attribute값이 바뀔 때 렌더링도 자동으로 최신화해주는 것도 알겠는데..
??? : attribute는 텍스트만 넘겨줄 수 있고, attribute를 감지하는 것이지 엘리먼트 내부의 상태값을 감지하는 것은 아니지 않나?
객체가 변했을 때 렌더링이 자동으로 일어나게 할 수 없을까?
customElements을 그렇게 만들어 보겠습니다.
class MyProxyElement extends HTMLElement {
constructor() {
super();
this.state = new Proxy({ value: 'init value' }, {
set: (obj, prop, value) => {
obj[prop] = value;
console.log('나 바뀜!')
this.render();
return true;
},
});
this.render();
}
render() {
this.innerHTML = `현재 상태는? : ${this.state.value}`;
}
}
export default MyProxyElement;
어떤 state를 Proxy로 작성하게 되면, 특정 상태를 감시할 수 있습니다.
Proxy 객체를 사용하면 어떤 객체의 작업을 가로채서 재정의를 할 수 있습니다.
이 객체에 대한 설명은 MDN이나 모던JS 문서에도 잘 나와있지만,
이 블로그에 있는 글도 다양한 사용법을 소개해줍니다.
위의 문서를 참고해보면 다음과 같은 해석이 가능합니다.
this.state에 어떤 객체 { value: 'init value' }
를 감시 대상자로 지정하고, 그 객체가 특정한 어떤 행동을 했음을 감지했을 때, 다음 행동으로 동작하게 합니다.
이 설명이 다소 복잡하여 좀 더 상세하게 예시를 들면
// 위 클래스의 생성자 내부를 가져온 것 입니다.
this.state = new Proxy({ value: 'init value' }, {
set: (obj, prop, value) => {
obj[prop] = value;
console.log('나 바뀜!')
this.render();
return true;
},
});
클래스 필드로 상태를 등록할 때, Proxy가 중간에 value를 가로채서 변화를 감지할 수 있습니다.
get 옵션을 준다면 값을 읽어들일 때, set 옵션을 준다면 값을 재정의할때 등 여러 상황의 이벤트를 감지할 수 있게 됩니다.
즉, 초기값으로 this.state.value는 ‘init value’를 가지게 될 것입니다.
하지만 이 객체는 그냥 객체가 아닌 Proxy 객체에 의해 감시를 받고 있게 됩니다.
바깥에서는 이 객체가 감시 받는 중인지 잘 모르겠지만요!
(감시라는 표현이 맞는지 모르겠지만 이해를 돕기 위해 이렇게 설명합니다.)
위에서 만든 클래스를 정의해주고
customElements.define('my-proxy', MyProxyElement);
html에서도 호출해봅니다.
<my-proxy id="myProxy"></my-proxy>
그리고 이 객체의 상태를 업데이트 하기 위한 버튼을 생성 해보겠습니다.
<button onclick="changeProxyState()">상태를 바꿔보자</button>
function changeProxyState() {
const myProxy = document.getElementById('myProxy');
myProxy.state.value = 'new value'
}
그리고 이 버튼을 눌러보면
현재 상태는? : init value
에서
현재 상태는? : new value
으로 스스로 바뀌는 것을 확인할 수 있습니다.
이 버튼은 그저 단순히 이 엘리먼트의 value 값을 수정했을 뿐인데, 왜 재렌더링이 됐을까요?
콘솔창도 열어보면, 버튼을 눌렀을 때 나 바뀜!
도 출력됨을 확인할 수 있습니다.
즉, Proxy객체의 setter가 value 값이 새로 쓰일 때를 감지하여 재 렌더링을 유도했음을 확인할 수 있습니다.
꼭 위의 예제처럼 state를 직접 수정하지 않아도, 간접적으로 수정하면 그 값이 자동으로 변경되는 것을 확인할 수 있게 됩니다.