Unhandled Runtime Error
Error: localStorage is not defined
✔️ 원인
localStorage는 브라우저 환경에서만 존재함,
서버에서 렌더링할 때는 localStorage가 없는데, 직접 접근해서 에러 발생함!
✔️ 문제 코드 (SSR 환경에서 localStorage 직접 접근)
<ShopDetailNavigation
shopId={params?.id}
activeTab="designer"
reviewCount={
JSON.parse(localStorage.getItem("reviews") || "[]").filter(
(review) =>
review.shopId === Number(params?.id) &&
review.status === "published"
).length
}
/>
✔️ 수정 방법
1) localStorage 접근을 useEffect로 옮기고, 상태로 관리
const [reviewCount, setReviewCount] = useState(0);
useEffect(() => {
if (typeof window !== "undefined") {
const reviews = JSON.parse(localStorage.getItem("reviews") || "[]");
const count = reviews.filter(
(review) =>
review.shopId === Number(params?.id) &&
review.status === "published"
).length;
setReviewCount(count);
}
}, [params?.id]);
2) ShopDetailNavigation에 reviewCount 상태 전달
<ShopDetailNavigation
shopId={params?.id}
activeTab="designer"
reviewCount={reviewCount}
/>
-> localStorage 접근 코드를 useEffect로 옮기고, reviewCount를 상태로 관리하여 ShopDetailNavigation에 전달하면
SSR 환경에서도 에러 없이 동작한다.
기존 코드 자체는 클라이언트용이지만,
Next.js의 특성상 SSR 구조에서는 처음에 서버에서도 실행될 수 있기 때문에
서버에는 없는 localStorage에 바로 접근하면 에러가 발생할 수 있다.
그래서 아래처럼 브라우저 환경에서만 localStorage를 사용하도록 조건을 넣는 것.
if (typeof window !== "undefined") {
// localStorage 사용
}
- 브라우저 환경: window 객체가 존재한다.
- 서버(SSR) 환경: window 객체가 존재하지 않으므로 undefined.
브라우저(클라이언트) 환경에서만 존재하는 전역 객체
브라우저에서 자바스크립트가 실행될 때,
웹페이지(탭) 하나당 하나의 window 객체가 자동으로 만들어진다.
이 객체는 브라우저의 창(window)을 대표하며,
localStorage, alert, document, location 등 브라우저에서 제공하는 여러 기능과 속성에 접근할 수 있게 해주는 역할을한다.
예시:
window.localStorage.getItem("key"); // localStorage 사용
window.alert("안녕하세요!"); // 알림창 띄우기
window.location.href // 현재 페이지 주소
서버(SSR) 환경에는 window가 없고,
브라우저에서만 window가 있기 때문에
이 객체가 있으면 "지금 브라우저에서 실행 중"임을 알 수 있다.
예약완료 후 페이지가 새로고침되어 최신 예약 정보 반영하기.
// 예약 완료 알림 표시
alert(`예약이 완료되었습니다.
디자이너: ${designer.name}
시술: ${selectedServiceObj.name}
가격: ${selectedServiceObj.price.toLocaleString()}원
날짜: ${selectedDate}
시간: ${selectedTime}`);
window.location.reload(); //추가
onClose();
};