sveltekit) window is not defined, 왜 나오는거야?

김방토·2024년 3월 7일

svelte

목록 보기
1/3

window가 없긴 왜 없어...?!

보통 이 오류를 마주한다면, SSR 방식의 프레임워크를 사용하고 있을듯 하다.
window는 어디서나 쓸 수 있다는 CSR에 익숙해진 나의 착각... 다른 사람들도 하고있지 않을까?

window, 어디에도 없지만 어느 곳에나 있겠죠

어디에도 없지만 어느 곳에나 있겠죠
가능하리라 믿어요

내가 만들어놓은 커스텀 훅 중에, 이런 훅이 있었다.

export const getAPIInfo = () => {
	const userId = window.localStorage.getItem('userId');
  
    ...
}

window의 localStorage에서 뭔가를 꺼낼때 쓰는 훅이다.
저장해놓은게 많아서 편하게 쓰려고 한번에 묶어놨었고, 실제로 문제없이 잘 동작했다.

그러다가 화면에서 userId를 보고싶다는 요청이 와서, 바로 div에서 호출해서 변수로 넣어주었는데...

<div class="text-bold">{getAPIInfo().userId}, 환영합니다.</div>

잘 사용하던게 안됐을때의 충격은 몇번을 받아도 타격이 크다...

왜 이런일이 발생하나요? window는 어디에서나 쓸수 있다면서요😵‍💫

sveltekit의 동작 방식 때문이다. (공식문서의 렌더링 부분 참고)
나는 현재 sveltekit을 사용하고 있고, sveltekit은 기본적으로 SSR 방식으로 동작한다.

일반적으로, SvelteKit은 서버에서 먼저 페이지를 렌더링하고 해당 HTML을 클라이언트로 보내어 거기에서 활성화합니다. 만약 ssr을 false로 설정하면, 빈 '셸' 페이지를 렌더링합니다. 이것은 페이지가 서버에서 렌더링될 수 없는 경우 유용합니다 (예를 들어 브라우저 전용 글로벌 변수인 document을 사용하는 경우), 그러나 대부분의 상황에서 권장되지 않습니다(부록을 참조하십시오).

공식문서 해석본이고, 진하게 표시해놓은 부분을 잘 봐야 한다. 브라우저 전용 글로벌 변수!
window 객체도 포함되는 설명이다.
잘 읽어보면 ssr을 false로 설정해서 이 상황을 해결할 수 있지만, 별로 추천하지는 않는다고.

그럼 어떻게 해결할까요?

해결 방식은 여러가지가 있을 것이다.
1. ssr을 사용하지 않기
2. (sveltekit) store 변수를 만들어 구독하기
3. window 객체가 있는지를 확인하는 조건문을 사용
4. 선언된 변수 사용하기

2번이 sveltekit 성격과 잘 맞는 예제지만, 페이지 두개짜리에 사용하기엔 효율성이 좀 떨어지는 듯 하기때문에 탈락.
(페이지 갯수가 늘어나고, 변수의 변동이 잦다면 정말 좋은 방식일것 같고... 너무 써보고싶다...!)
3번은 나중에 봤을때 의미 불명의 코드일것 같아서(이 사실을 모르고 봤을때-나는 내 기억력을 믿지 않는다- 도대체 window 객체가 있는지를 왜 확인하지? 라는 생각이 들수도 있지 않을까 싶어서) 탈락.

나는 변수를 먼저 선언하고, 페이지 마운트 시에 변수에 할당하는 방식을 선택했다.

// 변수 선언
let user: string;

// mount시 변수에 값 할당
onMount(async() => {
  const {userId} = getAPIInfo();
  
  // window.localStorage.getItem은 string | null 타입이고,
  // user는 string 타입이기 때문에 null이 아닐때만 할당 가능
  if(userId) user = userId;
})
<div>{user}님, 환영합니다.</div>

이렇게 하면 컴포넌트가 마운트되었을 때(컴포넌트가 화면에 나타날 때) localStorage에서 userId를 가져와서 user 변수에 할당한다.

그 후에는 템플릿에서 {userId}님, 환영합니다.를 사용하여 userId를 출력하고,
svelte는 window 객체에 직접 의존하지 않고, 컴포넌트 라이프사이클 내에서 localStorage에 접근하게 만들 수 있다.

업로드중..

문제없이 잘 동작함을 확인했다!

profile
🍅 준비된 안드로이드 개발자 📱

0개의 댓글