전역 상태 관리 라이브러리를 사용할 수 없었습니다.
창 간의 상태를 자동으로 공유하지 못하지 못하는 문제가 발생했습니다. 보통 전역 상태관리 라이브러리 들은
한 개의 React 애플리케이션 내에서 상태를 공유 하는데 초점이 되어있다.
브라우저 창/탭마다 메모리 공간이 따로 분리되어 있기 때문에 새창이 열리면 그 창은 새로운 독립적인 자바스크립트 실행 환경을 가지게 됩니다. 이 환경은 현재 페이지에서의 전역 상태와 완전히 분리되어 있어, 전역 상태를 직접 사용할 수 없다.
🧐 결론
전역 상태 관리 라이브러리를 못 쓴다기 보다는 , 브라우저 창 간에 직접적인 상태 공유가 안 되기 때문에 별도의 동기화 방식이 필요한 상황이라고 보는게 맞다.
이러한 문제를 해결하기 위해 이번에는 DispatchEvent 를 사용해 볼까 합니다.
DispatchEvent 는 DOM 요소(또는 window 객체)에서 특정 이벤트를 수동으로 발생시키는 메서드입니다.
이 메서드를 통해 프로그램적으로 사용자 동작(클릭, 키 입력 등)이나 커스텀 이벤트를 트리거할 수 있습니다. 이벤트를 발생시키면 해당 이벤트에 연결된 리스너들이 실행됩니다.
설명보단 직접 코드를 보면서 확인하는게 편할듯 합니다.
우선 dispatchEvent 를 custom 해줄 로직을 작성합니다.
if (window) {
window.addEventListener("storage", (event) => {
if (event.key === "dispatch") {
if (typeof event.newValue !== "string") {
return;
}
const objData = JSON.parse(event.newValue as string);
window.dispatchEvent(
new CustomEvent(`dispatch:${objData.key}`, { detail: objData.data })
);
window.localStorage.removeItem("dispatch");
}
});
}
윈도우 에서 storage
이벤트가 발생하면, 이벤트를 받게됩니다. key 는 dispatch 가 아닐 경우는 넘어가며, value 값은 JSON.stringify 값으로 넣어주기 때문에 우선 string 이 아닐경우 return 처리합니다.
그 후, window.dispatch 이벤트에 new CustomEvent 를 넣어줘서
objData.key와 objData.data를 사용하여 dispatch:${objData.key}
라는 이름의 CustomEvent를 생성하고, detail 속성에 objData.data
를 담아 이벤트를 디스패치합니다.
이 이벤트는 다른 코드에서 dispatch:${key}로 이벤트를 감지해 사용할 수 있습니다.
간단한 페이지가 있습니다. 해당 증가 시키러 가기를 누르면, a 태그 target으로 새 페이지를 생성합니다.
이런식입니다.
자 이제 증가 시키기 코드를 보겠습니다.
const onChagneCount = () => {
window.localStorage.setItem(
"dispatch",
JSON.stringify({ key: "count", data: {} })
);
};
return (
<div>
<p>카운트 증가 시키는 페이지 입니다.</p>
<button
onClick={() => onChagneCount()}
>
증가 시키기 UP
</button>
정의한 대로, event.key 는 dispatch를 넣어주며, event.newValue 값은 로컬 스토리지에 저장하듯 값을 넣어주면 됩니다.
이제는 받는 부분을 보겠습니다.
const [count, setCount] = useState(0);
useEffect(() => {
function onChagenCount() {
setCount((count) => count + 1);
}
window?.addEventListener("dispatch:count", onChagenCount);
return () => {
window?.removeEventListener("dispatch:count", onChagenCount);
};
}, []);
window에서 dispatch:count 라는 이벤트를 구독할수 있습니다. 해당 이벤트가 동작하면, onChangeCount 함수가 실행되고, 나중에 clean up 되는 모습을 볼 수 있습니다.
이제는 시연 영상 입니다.
새로운 탭 페이지에서, 상태를 동기화 시키는 모습을 볼 수 잇었습니다.
해당 구현은 제가 예전에 웹뷰 작업하면서 어려움을 겪어 그부분을 해결하고자 이용했던 방법을 조금 바꿔서 next 에서 구현해본 방법입니다.
이상으로 글 마무리 하겠습니다.