목록에서 항목을 하나 삭제했더니, 새로고침된 화면에서 남아있던 다른 항목에
체크가 들어가 있었다. "어 이미 선택돼 있네?" 하고 그대로 삭제 버튼을 눌렀더니
오히려 "삭제할 항목을 선택해 주세요"라는 안내가 떴다.
분명 체크는 보이는데, 시스템은 아무것도 선택 안 됐다고 한다.
처음엔 "프론트 문제인가, 화면이 잘못 그려진 건가" 싶었는데,
원인은 코드 버그가 아니라 브라우저가 원래 제공하는 "자동복원" 기능이었다.
체크박스를 다루는 화면이라면 어디서든 만날 수 있는 함정이라 정리해둔다.
브라우저는 새로고침/뒤로가기 때 사용자가 켜놨던 체크박스를 알아서 다시 켜준다(자동복원).
편의 기능이지만, "보이는 체크박스"와 "실제 제출/판단 데이터"가 분리된 화면에서는 둘이 어긋나는 버그가 된다.
폼을 길게 작성하다 실수로 새로고침하거나, 다음 페이지 갔다가 뒤로 돌아왔을 때
입력값이 다 날아가면 불편하다. 그래서 브라우저는 입력 상태(텍스트, 체크 여부 등)를 기억했다가
되돌아오면 복원해준다. 대부분의 일반 폼에서는 고마운 기능이다.
체크박스라서 문제인 게 아니다. 진짜 기준은 이거다.
화면에 보이는 UI 상태와, 실제로 제출되거나 판단에 쓰이는 데이터가 같은 것인가, 따로 관리되는가?
체크박스 자체가 name 을 갖고 그대로 서버로 전송되는 구조.
체크박스는 화면 표시용일 뿐이고, 진짜 값은 따로(예: 숨은 hidden 필드)에
자바스크립트가 "클릭할 때마다" 채워 넣는 구조.
오늘 만난 버그가 바로 경우 2였다.
| 구조 | 보이는 것과 데이터 | 자동복원 처리 |
|---|---|---|
| 체크박스가 직접 name 으로 제출 | 일치 | 안 해도 됨 (편의 기능) |
| 체크박스는 표시용, 데이터는 따로 JS 로 누적 | 어긋날 수 있음 | 처리 필요 |
| 서버가 의도적으로 checked 를 출력하는 체크박스 | 서버 상태가 정답 | 건드리면 안 됨 (초기화 대상에서 제외) |
마지막 줄 주의: 모든 체크박스를 무조건 초기화하면 안 된다.
서버가 "원래 켜진 상태로" 내려준 체크박스까지 꺼버리면 그게 또 다른 버그가 된다.
초기화 대상은 "표시용 + 데이터 분리" 인 것만.
form 또는 input 에 붙여서 "이 폼은 복원하지 마"라고 브라우저에 요청.
<form autocomplete="off"> ... </form>
복원이 끝난 다음에 코드로 체크박스를 꺼주고 데이터도 비운다.
여기서 "언제 실행하느냐"가 핵심이다. 타이밍이 전부다.
[안 되는 방법] 페이지 중간에 그냥 박은 script
1. HTML 읽으며 체크박스 그림
2. script 실행 -> 체크 끔
3. 페이지 다 읽은 뒤 브라우저가 복원 -> 다시 켬 <- 우리 걸 덮어씀
결과: 여전히 켜져 있음 (졌다)
[되는 방법] window.onpageshow (또는 onload) 로 예약
1. HTML 읽으며 체크박스 그림
2. 페이지 다 읽은 뒤 브라우저가 복원 -> 켬
3. 그 다음 onpageshow 실행 -> 체크 끔 <- 마지막에 우리가 끔
결과: 빈 상태로 시작 (이겼다)
같은 "체크 끄기" 코드인데, 브라우저 복원보다 먼저 실행되면 덮어써지고,
나중에 실행되면 살아남는다.
사실 가장 깔끔한 건 "표시용 + 데이터 분리" 구조 자체를 안 만드는 것.
자동복원이 와도 어긋날 일이 없다. (제출 직전에 보이는 상태 그대로 읽으니까)
다만 이미 분리 구조로 짜인 기존 코드라면, 구조를 갈아엎는 비용보다
autocomplete off + onpageshow 초기화가 훨씬 싼 처방이라 그렇게 해결하는 경우가 많다.