서론
쇼핑몰에서 "최근 본 상품" 배너를 보신 적 있을겁니다.
어떤 페이지로 이동하든 항상 사이드 영역에 존재하면서 새로운 상품을 클릭할 때 마다 업데이트 해야합니다.
이걸 리액트 프로젝트에서 어떻게 구현해야할까요?
상품의 클릭 이벤트 시점에 클릭된 상품 정보를 최근 상품 목록 컴포넌트에 전달해야 합니다.
물론 state lifting, contextAPI,redux 등의 방법이 떠오릅니다. 하지만 이 모든 방법이 여의치 않은 상황이라면 event 버스를 이용한 방법을 고려해볼 수 있습니다.
Event Bus
이벤트 버스
이벤트 버스(Event Bus)는 소프트웨어 아키텍처 패턴 중 하나로, 애플리케이션 내의 다양한 컴포넌트들이 서로 통신할 수있도록 하는 중앙 허브 역할을 합니다.
const EventBus = {
on(event, callback) {
document.addEventListener(event, (e) => callback(e.detail));
},
dispatch(event, data) {
document.dispatchEvent(new CustomEvent(event, { detail: data }));
},
remove(event, callback) {
document.removeEventListener(event, callback);
},
};
export default EventBus;
구현을 보면 아시겠지만 바로 CustomEvent를 사용해도 되긴 합니다 하지만 확장성과 중앙 집중식 설계를 위해 모듈로 정의했습니다. typescript를 이용해 이벤트와 콜백의 타입을 정의할 수도 있습니다. events 패키지도 한번 참고 해주세요
아래는 상품 상세 페이지 입니다. 아래 코드에서 사용된 useEffectOnce는 react-use를 참고해주세요
페이지 방문 시점에 상품정보를 이벤트로 dispatch하면 됩니다.
import { EventBus } from './EventBus';
function ProductDetail({ product }) {
useEffectOnce(() => {
EventBus.emit('productViewed', product);
});
return (
<div>
<h1>{product.name}</h1>
</div>
);
}
최근 본 상품 목록 컴포넌트입니다.
EventBus에서 productViewed 이벤트를 구독하고 localStorage를 업데이트하고 있습니다.
import React, { useState, useEffect } from 'react';
import { EventBus } from './EventBus';
function RecentlyViewedProducts() {
const [recentProducts, setRecentProducts] = useState([]);
useEffect(() => {
const handleProductView = (product) => {
setRecentProducts(prev => {
const updated = [product, ...prev.filter(p => p.id !== product.id)].slice(0, 5);
localStorage.setItem('recentProducts', JSON.stringify(updated));
return updated;
});
};
// ✅productViewed 이벤트 구독
EventBus.on('productViewed', handleProductView);
// 초기 상태 로드
const savedProducts = JSON.parse(localStorage.getItem('recentProducts') || '[]');
setRecentProducts(savedProducts);
return () => {
EventBus.remove('productViewed',handleProductView)
};
}, []);
return (
<div>
<h2>최근 본 상품</h2>
<ul>
{recentProducts.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</div>
);
}
정리
간단하게 최근 본 상품 기능을 통해 렌더 트리에서 멀리 떨어져있는 컴포넌트간의 통신 방법에 대해서 알아봤습니다.
확실히 전역 상태관리와 비교했을 때 장단점이 있는 방식입니다. 전역상태 관리의 경우 말 그대로 관리되어야 할 상태이기 때문에 지속되는 데이터라는 점에서 차이점이 있습니다. 반면 eventBus의 경우
1. 일회성 이벤트: 특정 액션이 발생했음을 알림 (notification)
2. 마이크로프론트앤드: 여러 독립적 애플리케이션 간 통신에 활용
3. 디버깅 및 로깅: 시스템 전반의 이벤트를 추적하고 로깅
4. 상태 변화 트래킹: 특정 상태 변화에 따른 이벤트 처리
등 이벤트라는 특징에 어울리는 상황이 존재하기 때문에 전역 상태관리와 별개로 기억해둘 필요가 있습니다.
'react' 카테고리의 다른 글
[Nextjs] 다국어(i18n, internationalization) 적용하기 (0) | 2024.07.19 |
---|---|
[Nextjs] next13에서 react-query의 필요성 (0) | 2024.06.27 |
[설계] 의존성 역전으로 변경에 유연한 설계하기 (0) | 2024.06.26 |
[설계] Compound Pattern으로 변경에 유연한 컴포넌트 설계하기 (0) | 2024.06.24 |
실무에서 가장 많이 실수하는 useEffect 사례 (0) | 2024.06.23 |