11월 12일에 대하여

11월 12일에 대하여

2025-11-12

오늘 한 일

1. 블로그 > 캘린더 UI 페이지 구현 : 학습 내역 시각화하기 위한 목적

꾸준히 학습은 하지만, 분명 무언가를 하고 있지만 한 게 아무것도 없는듯한 감정이 들고, 돌아보면 한 거는 있지만 또 다시 생각해보면 한 게 없는듯한 악순환에 놓인 기분이었다. 그래서 시각화했을 때 많은 위안을 받아서 계속 미루어왔던 로그를 작성하기로 함. 그래서 나의 목적에 캘린더형 UI가 가장 적합하다고 봐서 블로그에 캘린더 UI로 로그를 모아서 볼 수 있는 페이지를 추가하기로 함.

배운 점

1. 트러블슈팅 : URL은 ?m=2025-10인데, 로그에는 계속 2025-11만 찍히던 이슈

[배경]

- 주소창: http://localhost:4321/dev-logs?m=2025-10
- 콘솔 로그: month는 계속 2025-11 (현재 달)만 출력

[원인]

SSG(정적 프리렌더) + 쿼리 파라미터

Astro는 SSG인데, 빌드할 때 /dev-logs를 한 번 렌더링해서 HTML 파일로 만들어 둔다. 이때 Astro.url / Astro.request.url이 보는 값은 “쿼리 없는 /dev-logs” 뿐이게 된다. (?m=… 정보 없음)

const monthParam = searchParams.get("m"); // 항상 null
const month = monthParam ?? defaultMonth; // -> 항상 defaultMonth(현재 달)

그래서 브라우저에서 ?m=2025-10으로 들어가도 서버는 “이미 빌드된 /dev-logs HTML”을 그대로 보내준다. 그 HTML 안에 들어있는 month 값은 빌드시 계산된 2025-11 그대로 보이게 되면서 주소창은 10월, 내부 변수는 계속 11월이라는 이상한 상황이 발생된 것이다.

정리하자면 빌드 시점과 요청 시점의 불일치 때문이다. 쿼리 파라미터는 서버 코드를 다시 실행 시키지 못 하고 빌드 시점에만 한 번 실행되고 이후에는 그대로 계속 사용하는 것이다. 따라서 요청 들어올 때마다 서버에서 다시 렌더링하게 하면 해결이 되는 것이다.

[해결 방법]

=> 요청 → SSR → month 계산 → HTML 반환

이 페이지는 쿼리 파라미터에 따라 내용이 바뀌는 동적 페이지니까,

export const prerender = false; // SSR

이 페이지의 경우 매 요청마다 새로 렌더링하게 함. 그리고 URL 파싱 역시 Astro 공식문서에 따라 아래와 같이 변경함.

const { searchParams } = Astro.url;
const monthParam = searchParams.get("m");

On-demand rendering

SSR을 사용하기 위해서는 별도의 어댑터를 추가해야 하며 나의 경우 Vercel을 사용하고 있기 때문에 아래 명령어를 통해 추가해주었다. pnpm astro add vercel (참고)

2. 트러블슈팅 : 제대로 뒤로가기가 안 되는 이슈

[배경]

Q. 왜 캘린더 월을 url로 관리하지?

A. 새로고침을 하더라도 현재 보고 있는 월이 유지됨. 다른 방법으로는 완전 클라이언트 상태(ex. useState), 클라이언트 + localStorage

캘린더 UI의 경우 월을 변경할 수 있는데, 이때 월 추적을 url로 관리하였음.

http://localhost:4321/dev-logs?m=2025-10

그런데 페이지 레이아웃에 위치하는 Back(뒤로가기)를 클릭하면, [TO-BE] dev logs 페이지에서 뒤로가서 메인 페이지로 이동하는 것이 아닌 [AS-IS] dev-logs?m=2025-09 같이 월 변경 내역이 노출되는 이슈가 발생했다.

[원인]

a 태그의 경우 새로운 페이지로 이동하면서, 히스토리에 새 항목을 추가함. 그래서 메인 페이지로 나가기 전에, dev-logs의 “이전 월들”을 다 지나쳐야 하는 상태에 놓이게 되는 것이다.

[해결 방법]

=> 월 이동은 히스토리 “덮어쓰기”로 처리하기

  <a
    href={`?m=${prev}`}
    onclick={`event.preventDefault();location.replace(this.href);`}
    aria-label="Previous month"></a
  >

a 태그에 event.preventDefault()를 추가하고 location역시 현재 href로 대체하게 했다.

  • event.preventDefault()
    • a 태그의 기본 네비게이션을 막아 더 이상 자동으로 pushState 되지 않음
  • location.replace(this.href)
    • 현재 페이지를 this.href(예: ?m=2025-10)로 교체
    • 브라우저 히스토리에 새 항목을 추가하지 않고, “현재 스텝을 덮어쓰기” 하는 동작

추후 계획

  • 캘린더 UI에도 나만의 무언가를 담고 싶음. (참고)

    • 아이디어 : 지렁이 게임
  • 캘린더 컴포넌트 살펴보기

회고

처음에는 캘린더 컴포넌트를 하나의 컴포넌트로 만들었는데, 캘린더 월 변경 하는 걸 따로 두어서 같은 캘린더인데 분리되어 있는 인상이었음. 그래서 컴파운드 패턴으로 구현을 해 봄.

- 상태 준비
- month 문자열을 실제 날짜 정보로 변환
- 달력의 시작 요일 / 총 날짜 계산
- 월 이동(prev / next)
- 렌더링

- 월 변경 함수
- 한 달의 날짜 배열 만들기
- 렌더링에서 7개씩 끊기