[개발 기록] 새 창 팝업

블루·2022년 11월 8일
0

0. Intro

이 포스팅에서는 새 윈도우 창을 띄어주는 팝업을 구현한 과정과 이 과정에서 얻은 지식들을 정리해보고자 한다.


1. Search

(1) window.open(url, target, windowFeatures)

  • 웹 브라우저에서 팝업을 열기 위해서 사용할 수 있는 방법이다.
  • 메서드의 반환값으로 새로 만들어진 창 객체가 반환된다.
    • 창 생성에 실패하면 null을 반환한다.
    • 창 객체를 통해 새 창(팝업)의 close를 제어할 수 있다.

2. Coding

구현 과정에서 window.open으로 만들어진 창의 close를 제어하기 위하여 window.open의 반환값을 저장하는 로직이 필요했는데, 이를 useState hook을 사용하여 setState로 저장할 것인지, useRef hook을 사용하여 ref.current에 값을 저장할 것인지 고민이 되었다. 그래서 두 케이스 모두 구현해보고 좋은 쪽을 택하기로 했다.

(1) window.close 로직

  • 특정 컴포넌트가 언마운트되거나 부모 브라우저 창이 닫히면 새 창(팝업)이 닫히는 로직
const closeWindow = useCallback(() => {
    if (winObj !== null) {
      winObj.close();
    }
}, [winObj]);

useEffect(() => {
	window.addEventListener('beforeunload', ()=>{
		closeWindow()
	})

	return closeWindow
})

(2) window 객체를 State에 저장하는 경우

import React, { useCallback, useEffect, useState } from 'react';

function App() {
  const [showState, setShowState] = useState(false);
  const onBtnClick = () => {
    setShowState((showState) => !showState);
  };
  return (
    <div>
      <button onClick={onBtnClick}>show Component</button>
      {showState && <StateComp />}
    </div>
  );
}

const StateComp = () => {
  const [winObj, setWinObj] = useState<Window | null>(null);

  const closeWindow = useCallback(() => {
    if (winObj !== null) {
      winObj.close();
    }
  }, [winObj]);

  useEffect(() => {
    window.addEventListener('beforeunload', () => {
      closeWindow();
    });

    return closeWindow;
  }, [closeWindow]);

  return (
    <div>
      <button
        onClick={() => {
          setWinObj(window.open('https://www.naver.com/', '_blank', 'popup'));
        }}
      >
        Pop up!!
      </button>
    </div>
  );
};
  • state에 저장할 경우 Pop up 버튼을 여러번 누르더라도 state가 갱신되면서 이전의 state에 대해 winObj.close() 메서드를 실행해 이전 윈도우 객체는 close되고 하나의 윈도우만 남게된다.

(3) window 객체를 Ref에 저장하는 경우

import React, { useCallback, useEffect, useRef} from 'react';

function App() {
  const [showState, setShowState] = useState(false);
  const onBtnClick = () => {
    setShowState((showState) => !showState);
  };
  return (
    <div>
      <button onClick={onBtnClick}>show Component</button>
      {showState && <RefComp />}
    </div>
  );
}

const RefComp = () => {
  const winRef = useRef<Window | null>(null);

  const closeWindow = useCallback(() => {
    if (winRef.current !== null) {
      winRef.current.close();
    }
  }, []);

  useEffect(() => {
    window.addEventListener('beforeunload', () => {
      closeWindow();
    });
    return closeWindow();
  }, [closeWindow]);
  return (
    <div>
      <button
        onClick={() => {
          winRef.current = window.open('https://www.naver.com/', '_blank', 'popup');
        }}
      >
        Pop up!!
      </button>
    </div>
  );
};
  • ref를 사용할 경우에 Pop up 버튼을 여러번 누르면 누른 만큼 윈도우 팝업이 생성된다.
  • 또한 여러 팝업이 생성된 상태에서 컴포넌트가 언마운트되거나 브라우저가 닫힐 때, 가장 마지막에 생성된 윈도우만 close된다.
  • 따라서 useRef를 사용한 구현보다 useState를 사용한 구현이 적합하다는 판단을 내렸다.

3. TIL

Focus, Blur 이벤트

  • Focus : 앨리먼트가 포커스될 때 호출된다.
  • Blur : 앨리먼트에서 포커스가 사라졌을 때 호출된다.


참고자료

profile
개발 일지를 작성합니다

0개의 댓글