커스텀 이벤트 만들기
⭐ Custom Event 활용하기
Next로 작업을 하는 와중에, 다음과 같은 상황이 있었다.
layout.tsx에 특정 페이지와 하위 페이지에서만 적용 될 컴포넌트가 있는데, 여기에 undo / redo 버튼이 있다.
하지만 실제 undo / redo가 되어야 하는 건 edit 페이지 안에 있다.
layout.tsx는 edit 페이지에 직접적으로 state를 전달할 수 없다.
이런 상황에서 undo / redo를 완성하려면 전역 상태 관리밖에 답이 없을까? 👀 사실 그런줄 알았는데 또 다른 방법이 있었다. 바로 브라우저의 CustomEvent다.
🎁 예제 살펴보기
MDN의 예제를 살펴보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// CustomEvent 생성
const catFound = new CustomEvent("animalfound", {
detail: {
name: "cat",
},
})
// 이벤트 수신기 등록
obj.addEventListener("animalfound", (e) => console.log(e.detail.name))
// 이벤트 발동
obj.dispatchEvent(catFound)
// 콘솔: cat
예제에서는 먼저 new CustomEvent를 통해 animalfound라는 사용자 정의 이벤트 객체를 생성했다. 이때 detail이란 이벤트에 담아 보낼 데이터를 실어두었다.
이미 설정되어있는 click 이벤트처럼 addEventListener를 활용해 미리 만들어 둔 animalfound이벤트를 실행시킨다.
이때 e에는 미리 만들어 둔 catFound 객체가 전달된다.
1
2
3
4
5
6
e = {
type: "animalfound",
detail: {
name: "cat",
},
}
그래서 최종적으로 콘솔에 cat이 찍히게 된다.
1
2
3
4
5
6
7
// 이벤트 수신기 등록
obj.addEventListener("animalfound", (e) => console.log(e.detail.name))
// 이벤트 발동
obj.dispatchEvent(catFound)
// 콘솔: cat
👍 내 코드에 적용하기
그러면 undo와 redo를 만들어보자.
1
2
3
const handleUndo = () => {
window.dispatchEvent(new CustomEvent("undo"))
}
먼저 layout.tsx에 사용자가 클릭할 버튼을 만들고 onClick이벤트를 눌렀을 때 함께 발생할 커스텀 이벤트를 등록한다.
1
2
3
4
5
6
7
8
9
useEffect(() => {
const handleUndoEvent = () => handleUndo()
window.addEventListener("undo", handleUndoEvent)
return () => {
window.removeEventListener("undo", handleUndoEvent)
}
}, [handleUndo])
그 다음 edit 페이지에서 undo 이벤트가 발생할 경우 실행할 수 있도록 기다리는 useEffect를 작성한다.
그리고 실제 undo 이벤트가 발생시 어떻게 작동해야 하는지에 대한 handleUndo함수를 작성한다.
1
2
3
const handleUndo = useCallback(() => {
//코드 작성
}, [storeUndo])
즉 최종 흐름은 다음과 같다.
1
2
3
4
5
6
7
8
9
layout 버튼 클릭
↓
dispatchEvent('undo')
↓
edit에서 이벤트 감지
↓
handleUndo()
↓
실제 undo 로직 실행
이렇게 하면 간단하게 원하는 기능을 구현할 수 있다.