[JS] 웹뷰 페이지간 상태 동기화 DispatchEvent

houndhollis·2024년 10월 21일
1

웹뷰 에서의 문제점.

전역 상태 관리 라이브러리를 사용할 수 없었습니다.
창 간의 상태를 자동으로 공유하지 못하지 못하는 문제가 발생했습니다. 보통 전역 상태관리 라이브러리 들은
한 개의 React 애플리케이션 내에서 상태를 공유 하는데 초점이 되어있다.

브라우저 창/탭마다 메모리 공간이 따로 분리되어 있기 때문에 새창이 열리면 그 창은 새로운 독립적인 자바스크립트 실행 환경을 가지게 됩니다. 이 환경은 현재 페이지에서의 전역 상태와 완전히 분리되어 있어, 전역 상태를 직접 사용할 수 없다.

🧐 결론
전역 상태 관리 라이브러리를 못 쓴다기 보다는 , 브라우저 창 간에 직접적인 상태 공유가 안 되기 때문에 별도의 동기화 방식이 필요한 상황이라고 보는게 맞다.

이러한 문제를 해결하기 위해 이번에는 DispatchEvent 를 사용해 볼까 합니다.

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 에서 구현해본 방법입니다.

이상으로 글 마무리 하겠습니다.

profile
한 줄 소개
post-custom-banner

0개의 댓글