낙관적 서빙
오늘은 그동안 배운 걸 총 집합해서 Todo App을 만드는 실습 영상을 봤다.
과제를 하면서 여러개의 <li>
요소에 클릭 이벤트를 등록해야 했는데 innerHtml
로 렌더링하는 구조에서 이걸 어떻게 붙여야하나 고민했었다. 결국 요소 생성을 각각 따로 하고 이벤트리스터를 추가한 뒤 appendChild
하는 방법으로 구현했는데 더 깔끔한 방법이 있었다. 바로 이벤트 위임이다.
이벤트 위임이란 이벤트를 달고 싶은 여러 요소의 공통 부모에만 이벤트를 등록하고 그 곳에서 하위 요소들의 이벤트를 제어하는 방식이다.
이벤트는 부모에 달았는데 어떻게 하위 요소들을 구분해서 제어한다는 건가 싶지만 자바스크립트에는 이벤트 버블링과 캡처링이 있다.
이벤트 버블링은 특정 화면 요소에 이벤트가 발생했을 때 해당 이벤트가 상위 요소로 전달되면서 발생하는 현상을 말한다. 캡처링은 반대로 상위 요소에서부터 이벤트를 탐색해나가는 방식이다.
이를 통해 하위 요소에서 발생한 이벤트는 따로 막아주지 않는 한 부모 요소에서도 일어난다.
부모 요소가 하위 요소를 구분하는 방법은 Event.target
속성이다. Event.currentTarget
과 다르게 Event.target
은 전달되어 올라온 이벤트에서도 첫 이벤트 발생 요소를 가리킨다.
이벤트를 처리하고 싶은 요소에 하위 요소가 달려서 Event.target
값이 오염된다면 Event.target.closest
를 이용해서 처리할 수 있다.
만약 요소마다 다른 이벤트를 달아주고 싶다면 클래스 네임으로 구별할 수도 있지만 dataset
을 이용해서 구분하는게 의미론적으로 낫고 CSS를 처리하기에도 용이하다.
스타일을 구분할 때만 클래스 네임을 쓰고, 다른 정보들은 데이터셋을 쓰자는 것
아예 document
에 이벤트를 달아버리고 요소들에게 dataset
속성이 하고자하는 행동을 나타내도록 표시한 뒤 해당 속성에 따라 행동을 처리하도록 구현할 수도 있다. 이렇게 하면 요소 코드만 봐도 어떤 행동을 할 요소인지 명확하게 알 수 있다. 즉, 선언적 방식으로 행동을 추가할 수 있어진다.
또한 동적으로 생성되는 요소에 사용하기 좋다. 동적 요소에 하나하나 이벤트리스너를 다는 방식은 코드도 복잡해지지만 리스너를 제 때 제거해주지 않으면 메모리 누수가 일어난다. 대신 이벤트 위임을 사용하면 관리가 쉽고 메모리도 적게 쓰면서 누수 가능성도 줄어든다.
단점도 있긴 하다. Event.stopPropagation
을 하위 요소에서 쓸 수 없어지고 부모 요소가 응답할 필요없는 이벤트도 응답하게 되므로 CPU 부하가 늘어난다. 다만 중대한 수준은 아니고 이점이 더 많기에 다양한 라이브러리와 프레임워크에서 사용한다.
벨로그 클론 토이프로젝트에서 작성글 페이지를 구현할 때 좋아요 버튼은 애니메이션을 제대로 구현하는 것에만 중점을 뒀었다. 누르면 반응 애니메이션을 수행하고 좋아요 수 증감 api를 보냈는데 어찌보면 낙관적 업데이트를 적용한 거라고 볼 수 있을 것 같다.
당연히 실패 시 처리는 생각도 못해서 좋아요 0개짜리 초록 하트를 볼 수 있었을 거다.
낙관적 업데이트란 사용자가 보내는 요청이 성공할 것이라고 예상하고 프론트 단에서 선제적으로 UI를 업데이트하는 방식을 말한다. 이를 사용하면 사용자가 본인의 활동이 즉각적으로 반응한다고 느낄 수 있기 때문에 답답함을 줄이거나 중복 요청을 방지할 수 있다.
단 요청이 모종의 이유로 서버에서 처리가 실패했을 경우 유저에게 알리고 UI를 되돌리는 과정이 필요하다. 때문에 되돌리기 어려워지는 복잡한 요청에는 낙관적 업데이트를 사용하지 않는다.
프론트엔드 개발자 입장에서는 고려해야할 사항이 많아지지만.. 그런거 하라고 있는 거라고 한다.
낙관적 업데이트는 게임에서도 많이 쓰지 않나 싶은 생각이 들었다. 게임의 경우에서처럼 반응성이 중요하면서 신뢰성이 덜 필요한 부분에 사용하면 괜찮을 것 같다.