[NextJS] localStorage 에러핸들링 -localStorage is not defined-

hyo·2023년 1월 28일
7

NextJS

목록 보기
2/4
post-thumbnail

localStorage 에러

에러 원인

CSRSSR의 차이로 인한 에러!

Next.jsclient-side 렌더를 하기전에 server-side 렌더를 수행한다.
Next.js에서 제공하는 Server Side Rendering(SSR)에선 client-side에 존재하는 window, document 전역객체를 사용할 수 없다.
그래서 console.log(localStorage)만 코드에 써두고 실행시켜도

ReferenceError: localStorage is not defined
라는 에러가 나온다.

해결방법

1. typeof window !== 'undefined'

  • 페이지가 client에 마운트될 때까지 기다렸다가 localStorage에 접근해야함.
  • window 객체가 참조되지 않을 경우, undefined를 반환함.
if (typeof window !== 'undefined') {
  localStorage.getItem('accesstoken');
}

2. useEffect

  • useEffect는 렌더링이 되고 난 후 실행되기때문에 server-side에서는 실행되지 않는 CSR 전용 이벤트라고 생각하자.
  • useEffect는 렌더링 시 실행되므로, 초기 서버 빌드 시 useEffect 내부 코드는 실행되지 않는다.
  • useEffect는 client-side에서만 실행되므로 localStorage에 안전하게 접근 가능하다.
import React, {useState, useEffect} from 'react';

const Header = () => {
  const [isAuth, setIsAuth] = useState(false);

  useEffect(() => {
      if (
        localStorage.getItem('accesstoken') ||
        sessionStorage.getItem('accesstoken')
      ) {
        setIsAuth(!isAuth);
      } else {
        setIsAuth(false);
      }
    }, [
      localStorage.getItem('accesstoken'),
      sessionStorage.getItem('accesstoken'),
    ]);
  return (
    <div>
    {isAuth ? <>마이페이지</> : <>로그인페이지</>}
    </div>
  )
}

3. class로 모듈화시켜 사용

Next.js환경에서 window 객체에 접근 할 떄마다 위와 같은 방식을 사용하는게 번거로울수도 있어서 다른방법을 찾아보다가
어떤글을 보고 class로 모듈처럼 만들어서 써보려고 시도해보았고 결과는 편리하고 간단하게 사용할 수 있었다.
localstorage.ts

// localstorage.ts

class LocalStorage {
  constructor() {}

  static setItem(key: string, value: string) {
    if (typeof window !== 'undefined') {
      localStorage.setItem(key, value);
    }
  }
  
  // getItem 은 return 을 넣어줘야함! setItem, removeItem이랑 다르게 값을 보여주는녀석!
  static getItem(key: string) {
    if (typeof window !== 'undefined') {
      return localStorage.getItem(key);
    }
    // window객체 localStorage, sessionStorage는 값이 없을때 null
    return null; 
  }

  static removeItem(key: string) {
    if (typeof window !== 'undefined') {
      localStorage.removeItem(key);
    }
  }
}

export default LocalStorage;
import LocalStorage from '../../../constants/localstorage';

const Header = () => {
  
  LocalStorage.setItem('accesstoken', 'access토큰 넣어본다!');
  console.log(LocalStorage.getItem('accesstoken')) // -> 'access토큰 넣어본다!'
  
  return (
    <div>
      헤더!
    </div>
  )
}
profile
개발 재밌다

0개의 댓글