-
[Bug Fix] Next.js 14 App Router 버전 window is not defined 문제 해결Front-end 개발/FE 버그 2024. 11. 20. 09:19
Problem
프로젝트를 진행하면서 로컬스토리지로부터 객체 데이터를 가지고 와서, 파싱하고 state에 저장하는 과정이 반복해서 수행되고 있었다. 반복되는 과정의 코드를 줄이기 위해 커스텀 훅 useLocalStorage을 만들었다.
로컬스토리지는 브라우저의 저장소로 데이터를 key-value 쌍으로 저장할 수 있다. 그런데 Next.js는 서버 사이드 렌더링을 지원하기 때문에, 서버 측에서 코드가 실행될 때 문제가 발생하게 된다. 로컬스토리지를 사용할 때는 Window 객체가 존재하는 클라이언트 사이드에서만 접근해야 한다.
Next.js 클라이언트 컴포넌트에서는 일반적으로 useEffect를 사용하여 컴포넌트가 마운트된 후에 로컬스토리지에 접근하는 방식을 사용한다. 하지만 내 상황에서는 useState를 초기화 해야 하는 과정에서 로컬스토리지 값을 사용하고 싶었기에 맞지 않았다.
'use client'; import { useState } from 'react'; export default function useLocalStorage<T>(key: string, initialValue?: T) { const [storedValue, setStoredValue] = useState<T>(() => { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; }); const setValue = (value: T) => { setStoredValue(value); window.localStorage.setItem(key, JSON.stringify(value)); }; return [storedValue, setValue] as const; }
Solution
이 문제는 서버측에서 클라이언트 컴포넌트를 Next.js 서버에서 실행할 때 발생하는 참조 에러이기 때문에 타입처럼 조건문으로 분기처리를 해줘야 한다. 즉, window 객체를 사용할 때 조건부로 클라이어트 사이드에서만 실행되도록 하면 된다.
만약 window 객체가 인식 안 될 경우, storedValue는 props로 받은 초기값으로 무조건 초기화 되어버린다. 반면에 window 객체가 인식되면 로컬 스토리지의 데이터를 가져와 초기화를 해준다. 로컬 스토리지가 비어 있다면 마찬가지로 props로 받은 초기값을 활용하여 초기화 한다.
'use client'; import { useState } from 'react'; export default function useLocalStorage<T>(key: string, initialValue?: T) { const [storedValue, setStoredValue] = useState<T>(() => { if (typeof window !== 'undefined') { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } return initialValue; }); const setValue = (value: T) => { setStoredValue(value); if (typeof window !== 'undefined') { window.localStorage.setItem(key, JSON.stringify(value)); } }; return [storedValue, setValue] as const; }
Other Solution
useEffect를 사용하는 방법에 대해 더 생각해봤는데,
일단 initialValue로 초기화하고 컴포넌트가 마운트 된 이후에 useEffect를 사용해서 setStoredValue로 sotredValue를 초기화 해주는 방법도 가능할 것 같다.
실제 프로젝트에서 문제 없는지 확인은 안했지만, 아래 코드도 문제없이 작동 할 것 같다.
'use client'; import { useEffect, useState } from 'react'; export default function useLocalStorage<T>(key: string, initialValue?: T) { const [storedValue, setStoredValue] = useState<T>(initialValue); const setValue = (value: T) => { setStoredValue(value); if (typeof window !== 'undefined') { window.localStorage.setItem(key, JSON.stringify(value)); } }; useEffect(() => { const item = window.localStorage.getItem(key); item && setValue(JSON.parse(item)) }, [key]) return [storedValue, setValue] as const; }
'Front-end 개발 > FE 버그' 카테고리의 다른 글
[Bug Fix] Next.js 14 App Router 버전 OAuth Session 동기화 문제 (0) 2024.11.17 [Bug Fix] parcel 실행/build Error : unable to open snapshot file (0) 2023.12.29