React로 웹 서비스를 개발하다 보면 외부 문서(약관, 동영상 등)를 보여주기 위해 iframe을 사용하는 경우가 있다. 최근 개인적으로 개발하고 있는 피트니스 앱 웹뷰의 약관 상세 페이지에서 iframe을 활용하던 중, "뒤로가기" 버튼을 눌렀을 때 예상치 못한 문제가 발생했다.
여러 약관 리스트 중 하나를 클릭하면 상세 페이지로 이동하고, 해당 약관 파일을 iframe으로 보여주고 있다. 사용자가 상세 페이지에서 다른 날짜의 약관을 선택하면, iframe의 src가 변경되어 다른 문서를 보여주게 된다.
이 상태에서 브라우저의 "뒤로가기" 버튼을 누르면, 한 번에 리스트로 돌아가지 않고, 여러 번 눌러야만 이동하는 문제가 발생했다.
<iframe
src={selectedTermUrl || initialTermUrl}
// src(selectedTermUrl)가 바뀔때마다 뒤로가기를 여러번 눌러야 약관 리스트 페이지로 뒤로가기 됨
allowFullScreen
frameBorder="0"
style={{
width: "100%",
height: "calc(100vh - 16.8rem)",
WebkitOverflowScrolling: "touch",
overflow: "auto",
}}
/>
문제의 핵심은 iframe의 동작 방식에 있었다.
iframe의 src가 변경될 때마다, 브라우저는 이를 "content navigation"으로 인식하여 window.history 스택에 추가하게 된다.
즉, React 앱의 URL은 바뀌지 않아도, iframe 내부의 문서 이동이 브라우저 히스토리에 쌓이게 된다. 이로 인해, 뒤로가기를 누르면 iframe 내부 문서만 이전 상태로 돌아가고, React 앱의 라우팅은 그대로여서, 사용자는 여러 번 뒤로가기를 눌러야만 원래의 리스트 페이지로 돌아갈 수 있는 것이다.
key 활용
React에서 key prop을 바꿔주면 해당 컴포넌트가 완전히 새로 마운트된다.
즉, iframe의 src가 바뀔 때마다 그에 맞는 동적인 key를 부여하면, React가 iframe을 완전히 새로 생성하게 되는 것이다. 이 원리를 통해 이슈를 해결할 수 있었다.
<iframe
key={selectedTermUrl || initialTermUrl}
src={selectedTermUrl || initialTermUrl}
allowFullScreen
frameBorder="0"
style={{
width: "100%",
height: "calc(100vh - 16.8rem)",
WebkitOverflowScrolling: "touch",
overflow: "auto",
}}
/>