React로 프로젝트를 진행하던 중 모달이 아닌 팝업창을 통해 데이터를 전달하고 전달 받는 케이스가 생겼다.
모달도 아니고 새 팝업창인데 어떻게 데이터를 주고 받아야하나 고민하던 차에 구글링과 chatGPT의 도움으로 해결하여 기록하고자 한다.
window.open
을 사용하여 팝업창을 열 때, 부모창에서 자식창에게 데이터를 넘겨주는 것은 직접적으로 불가능하다. 이는 브라우저의 보안 정책 때문이다. 그러나, 몇 가지 방법을 통해 데이터를 전달할 수 있다.
부모창에서 LocalStorage 또는 SessionStorage에 데이터를 저장하고, 팝업창이 열릴 때 해당 저장소에서 데이터를 가져올 수 있다.
// 부모창
localStorage.setItem('sendData', JSON.stringify(sendData));
window.open('popup.html');
// 팝업창
const sendData = JSON.parse(localStorage.getItem('sendData'));
URL의 쿼리 파라미터를 통해 데이터를 전달할 수 있다. 하지만 이 방법은 전달할 수 있는 데이터의 크기가 제한적이며, 복잡한 데이터 구조를 전달하기 어렵다.
// 부모창
const checkedListString = JSON.stringify(checkedList);
window.open(`popup.html?checkedList=${encodeURIComponent(checkedListString)}`);
// 팝업창
const urlParams = new URLSearchParams(window.location.search);
const checkedList = JSON.parse(decodeURIComponent(urlParams.get('checkedList')));
API를 사용하면, 도메인, 프로토콜, 포트가 다른 창 간에 안전하게 데이터를 전달할 수 있다. 이 방법은 복잡한 데이터 구조를 전달하는 데 적합하다.
// 부모창
const popup = window.open('popup.html');
popup.postMessage({ sendData }, '*');
// 팝업창
window.addEventListener('message', (event) => {
const { sendData } = event.data;
});
나는 목록에서 선택한 check박스의 id배열을 자식 팝업창으로 넘겨줘야 했는데 세가지 방법 중 첫번째 방법을 이용했다.
// 부모창
const [checkedList, setCheckedLists] = useState([]);
//'상태변경' 버튼 클릭
const _pupup = () => {
if (checkedList.length < 1) {
alert("상태를 변경할 목록을 선택해 주세요.");
return;
}
window.open(
"/searchConts",
"_winPkg",
"height=400, width=400, toolbar=no, scrollbars=no,resizable=yes"
);
// 로컬스토리지에 checkedList 값 저장
localStorage.setItem("checkedList", JSON.stringify(checkedList));
// window 객체에 parentCallback이라는 새로운 함수 추가
window.parentCallback = () => {
getContents();
setCheckedLists([]);
};
};
localStorage
setItem으로 checkedList라는 값을 저장시키는 방법을 사용했다.
window.parentCallback이라는 새로운 함수를 추가하여 이 함수가 실행될 때 getContents(새로운 리스트 데이터 조회)와 setCheckedLists(선택된 리스트 해제)를 동작하게 선언하였다.
자식창에서 부모창의 데이터를 받기 위해 아까 localStorage
에 저장한 값을 받아온다.
const concdss = JSON.parse(localStorage.getItem("checkedList"));
내 프로젝트에서는 concdss
라는 변수명으로 받았다.
자식창에서 '저장' 버튼을 클릭했을 때 부모창의 함수를 실행해 보겠다.
// 저장
const _postState = useCallback(() => {
contentAPI
.putContentStatus(concdss, consts, conrmk, token.id)
.then(() => {
localStorage.removeItem("checkedList");
window.opener.parentCallback();
window.close();
})
.catch((error) => {
console.error("Error:", error);
});
});
저장 버튼을 클릭 했을 때, PUT method로 API를 호출하고 성공적으로 데이터를 보내면 localstorage에 저장한 checkedList 값을 삭제시켜준다.
부모창에 선언한 parentCallback함수를 실행시켜 새로운 데이터를 가져오고 체크박스를 전체 해제 시킨다.
공감하며 읽었습니다. 좋은 글 감사드립니다.