오늘 챌린지반 수업에서는 발행자/구독자 패턴을 배우고 이것을 활용하여 Potal로 Toast를 만드는 과제를 받았다. 과제를 실행하기에 앞서 수업에서 사용된 코드를 가져와 분석해보는 시간을 가졌다.
아래가 바로 발행자/구독자 패턴이다. 쉽게 말해 구독을 통해 이곳에 명령어(topic)와 그와 매칭되는 함수들(listeners)을
저장 (subscribe) 하고 그것들을 실행 (publish) 시킬 수 있도록 하는 것이다.
// PUB/SUB 패턴
const EventBus = () => {
// 명령어를 저장하는 곳
const topics = new Map();
const subscribe = (topic, listener) => {
// 가장 먼저 명령어를 저장함
// 값을 배열로 줌으로써 명렁어를 입력하면 여러 개의 함수를 실행할 수 있도록 함
if (!topics.has(topic)) {
topics.set(topic, []);
}
// 구독을 통해 명령어에 함수를 저장함
topics.get(topic).push(listener);
// 구독해제 클린업 함수
return () => {
// 명령어 topic에 있는 구독되어 있는 함수들
const listeners = topics.get(topic);
// 나의 구독listener 취소
listeners.splice(listeners.indexOf(listener), 1);
};
};
// 명령어를 입력하여 해당 명령어에 구독된 함수들을 실행함
const publish = (topic, data) => {
// 구독되어 있지 않으면 실행되지 않음
if (!topics.has(topic)) return;
// 구독되어 있는 경우
// 명령어topic에 저장된 함수들listeners을 실행
topics.get(topic).forEach((listener) => listener(data));
};
return { subscribe, publish };
};
// subscribe함수와 publish함수가 담긴 객체
const bus = EventBus();
export default bus;
이러한 구조의 장점은 구독과 실행이 분리되어 있을 수 있다는 것이다. 아래 함수를 보면 <Toast />가 구독한 함수인데, 이와 별도로 showToast를 불러와서 실행시키는 모습을 확인할 수 있다. Toast는 유효한 범위 내에 있다면 위치가 자유로워지는 것이다.
function App() {
return (
<div className="App">
<Toast />
<h1>React Event Bus Toast Example</h1>
<button onClick={() => showToast("This is a toast message!")}>
Show Toast
</button>
</div>
);
}
<Toast/> 구독subscribe
const Toast = () => {
// 실행시킬 메세지들을 저장하는 상태값
const [toasts, setToasts] = useState([]);
useEffect(() => {
// 구독하면서 이 함수를
//"SHOW_TOAST" 토픽의 topic
// handleToastEvent 리스너로 저장함 listener
const handleToastEvent = (toast) => {
// 메세지 저장
setToasts((prevToasts) => [...prevToasts, { id: Date.now(), ...toast }]);
// 시간이 지나면 가장 처음 실행된 메세지부터 삭제
setTimeout(() => {
setToasts((prevToasts) => prevToasts.slice(1));
}, 1500);
};
// subscribe 실행
// unsubscribe은 subscribe이 결과값으로 반환하는 구독해제 함수
const unsubscribe = bus.subscribe("SHOW_TOAST", handleToastEvent);
// subscribe가 실행 후 반환하는 구독해제 함수
// 를 실행하여 구독해제
return () => unsubscribe();
}, []);
// 포탈을 열어서 이 함수가 실행되면
// 2번째 인자의 위치에(이 경우 body)
// 1번째 인자를 집어넣음
return createPortal(
<div className="toast-container">
{toasts.map((toast, index) => (
<div key={index} className="toast">
{toast.message}
</div>
))}
</div>,
document.body
);
};
showToast 실행publish
// Toast 파일에서 저장한 SHOW_TOAST에 구독한 함수를 불러와서
// 매개변수message의 값을 넣어 실행시키도록 하는 함수
export const showToast = (message) => {
// Toast에서 구독으로 저장한 명령어들을
// 첫번째 인자 "SHOW_TOAST"키를 통해 불러와서
// 두번째 인자 message를 넣어 실행시킴
// SHOW_TOAST 명렁어에 구독된 함수가 여러개면 여러 개가 실행됨
bus.publish("SHOW_TOAST", { message });
};
이렇게 Toast의 간단한 로직을 알게 되었는데... 이제부터 여기에 기능을 추가해야 한다. 힘내자...
'배운 코드 정리' 카테고리의 다른 글
min, splice, filter, apply (0) | 2024.07.11 |
---|---|
indexOf, sort (0) | 2024.07.09 |
돌아온 정수 제곱근 판별 (0) | 2024.07.02 |
자연수 뒤집기 (0) | 2024.07.01 |
배열의 평균 값 (0) | 2024.06.21 |