문제 상황
웹사이트를 개발하다보면 click, scroll, resize 등과 같은 다양한 DOM 이벤트를 사용하게 된다. 하지만 이러한 이벤트 외에도 특정 이벤트에 맞춰 특정 액션을 발생시키고 싶은 경우는 매우 많다. 이럴 때 CustomEvent는 매우 유용하다. 이 API는 말 그대로 사용자가 지정하는 이벤트를 만드는 것이다.
if (!data) {
return (
<Container>
<Loading/>
</Container>
);
};
const Loading = styled.div`
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center !important;
align-items: center !important;
z-index: 100;
`;
나는 커스텀 이벤트를 로딩 컴포넌트를 불러올 때 주로 사용했다. 원래는 로딩 컴포넌트를 사용하는 컴포넌트 마다 위와 같은 조건부 렌더링을 해주었다. 매번 이런 식으로 하는 것이 귀찮았기 때문에 loading 이벤트가 발생할 때 최상단 컴포넌트에서 이벤트를 듣고 액션을 취하는 방법을 떠올렸다.
해결 방법
export function triggerCustomEvent(eventType, data) {
const event = new CustomEvent(eventType, { detail: data });
window.dispatchEvent(event);
}
위와 같이 커스텀 이벤트를 트리거 하는 함수를 만들었다.
window.addEventListener("loading", e => {
setLoading(e.detail.isOpen);
});
if (!loading) {
return (
<Container>
<Loading/>
</Container>
);
};
그리고 loading 이벤트를 수신하는 addEventListener를 최상단 컴포넌트에 등록했다. 여기서 수신하는 이벤트 객체의 detail 값에 따라 loading 상태 값이 달라지게 만들었다. 이렇게 되면 컴포넌트 마다 덧붙였던 로딩 컴포넌트 조건부 렌더링 코드를 지워도 된다!
const onCartClick = async (e, id) => {
e.stopPropagation();
triggerCustomEvent('loading', { isOpen: true });
await addItem(id, 1);
await Promise.all([mutateCartData(), mutateTotalData()]);
setShowCart();
triggerCustomEvent('loading', { isOpen: false });
};
원래 존재했던 조건부 렌더링 코드를 지우고 로딩 컴포넌트가 필요한 곳에 이런 식으로 트리거 함수만 적어주면 완성!
도움이 된 자료
커스텀 이벤트 디스패치, https://ko.javascript.info/dispatch-events, (2022.01.19)