[Next.js] SSR에서 Web Storage에 접근하는 방법

Jane·2023년 8월 23일
1

Next.js

목록 보기
9/12
post-thumbnail

🚨 ReferenceError: localStorage is not defined

import { useState } from "react";

export default function Home() {
  let value;

  value = localStorage.getItem("pw") || "";

  const [pw, setPw] = useState(value);

  const saveToLocalStorage = (e) => {
    e.preventDefault();
    localStorage.setItem("password", pw);
  };

  return (
    <div>
      <label htmlFor="pw">Write your password here.</label>
      <form onSubmit={saveToLocalStorage}>
        <input
          id="pw"
          type="password"
          value={pw}
          onChange={(e) => setPw(e.target.value)}
        />
        <button type="submit"></button>
      </form>
    </div>
  );
}

위와 같이 비밀번호를 localStorage에 저장하는 코드를 Next.js 프로젝트에서 작성했다고 가정해보자.
그리고 이 코드를 실행시키면,

ReferenceError: localStorage is not defined

이러한 에러가 발생한다.

🤔 왜 발생하는 에러일까?

  1. Next.js는 Client-Side를 렌더링하기 전 Server-Side 렌더링을 수행한다.
  2. Next.js에서 제공하는 SSR에서는 window, document와 같은 브라우저 전역 객체를 사용할 수 없다.
  3. window 객체는 Client-Side에만 존재한다.
    • WebStorage는 window의 객체이다.
    • 페이지가 클라이언트에 로드되고, window 객체가 정의되기 전까지는 window.localStorage에 접근할 수 없다.
  4. 따라서 코드가 서버에서 컴파일 될 때, localStorage 객체가 존재하지 않아 에러가 발생하는 것이다.

🧐 어떻게 해결할 수 있을까?

  • 이러한 에러를 해결하기 위해서는 localStorage에 접근하기 전에 클라이언트 측에 페이지가 마운트 될 떄까지 기다려야 한다.

typeof window !== 'undefined'

  • window 객체가 정의되었는지 확인하는 방법
if (typeof window !== "undefined") {
  // localStorage 관련 작업 수행 코드
  value = localStorage.getItem("pw") || "";
}
  • 페이지가 Client-Side에 마운트 될 때까지 기다렸다가 localStorage에 접근한다.
  • window 객체가 참조되지 않을 경우 undefined를 반환한다.
    • localStorage는 window 객체 내부의 객체이므로 window 객체가 정의되지 않은 서버에서는 localStorage 관련 코드가 실행되지 않을 것이다.
  • 이를 통해 localStorage에 접근하기 전 localStorage가 정의된 상태라는 것을 보장한다.

typeof의 확장; class로 만들어서 사용하기

class LocalStorage {
  constructor() {}

  static setItem(key: string, item: string) {
    if (typeof window !== "undefined") {
      localStorage.setItem(key, item);
    }
  }

  static getItem(key: string) {
    if (typeof window !== "undefined") {
      return localStorage.getItem(key);
    }
    return null;
  }

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

export default LocalStorage;
  • 위와 같이 localStorage 관련 메서드를 클래스로 선언하여 사용할 수 있다.
// 사용방법
import LocalStorage from "../";

const saveToLocalStorage = (e) => {
  if (!e.target.value) return;
  e.preventDefault();
  LocalStorage.setItem("password", pw);
};

try-catch 문 사용하기

try {
  value = localStorage.getItem("pw") || "";
} catch (error) {}
  • 단순하게 try catch 블록으로 localStorage 접근 코드를 감쌀 수 있다.

🌟 useEffect

👩‍🏫 위의 방식들보다 더 "React"스러운 해결책입니다.
import { useEffect } from "react";

useEffect(() => {
  // localStorage 관련 작업 수행 코드
  value = localStorage.getItem("pw") || "";
}, []);
  • useEffect는 마운트 되었을 때 실행되기 때문에 CSR 전용 훅 함수이다.
    • 이 때문에 브라우저라는 확신을 줄 수 있고, not defined라는 에러에 대한 우려 없이 사용할 수 있다.
  • useEffect는 렌더링 시 실행되므로 초기 서버 빌드 시에 useEffect 내부에 위치한 코드는 실행되지 않는다.
  • useEffect는 Client-Side에서만 실행되므로 localStorage에 안전하게 접근할 수 있다.

🔎 References

참고 자료 모음
profile
An investment in knowledge pays the best interest🙃

0개의 댓글