Next.js와 브라우저 저장소

2023. 7. 14. 06:27Next.js

728x90
반응형

브라우저의 저장공간

브라우저에 데이터를 저장할 수 있는 공간을 먼저 알아보자!

 

개발자 도구 > Application에서 볼 수 있다.

 

1. Local Storage

  • 브라우저를 껐다가 켜도 남아있는다.
    ex) 비회원으로 장바구니 담기한 경우 저장
  • 보안상 중요한 데이터를 저장하는 것은 옳지 않다. console에 찍으면 다~ 나오기 때문,,

 

2. Session Storage

  • 브라우저를 끄면 사라진다.

 

3. Cookies

  • 브라우저와 백엔드 간 연결 시 데이터 전달 통로가 될 수 있다.
  • 지정한 시간이 지나면 사라진다.
  • 백엔드 API와 통신할 때 같이 보낼 수 있다.
  • 만료 시간을 지정할 수 있다.

이렇게 객체 형태로 저장해서 사용할 수 있다.

 

그런데,

Next.js 환경에서 이러한 브라우저 저장소에 접근하려고 하면 아래와 같은 에러가 발생하는 경우가 있다.

그 이유는 Next.js가 화면을 렌더링하는 원리에 있다.

 

Next.js가 화면을 렌더링하는 원리

브라우저에 주소를 치고 접속하면,
프론트엔드 서버로 접속해서 html, css, js를 다운받아와서 먼저 그림을 그려주고,
그 다음에 2차적으로 useQuery 등이 실행되어서 백엔드가 데이터를 꺼내와서 2차적으로 화면에 데이터를 그려준다고 알고 있었다.

 

사실 여기에 한 단계가 더 있다!! Pre-rendering -> hydration

 

(1) Pre-rendering

브라우저에서 yarn dev로 접속을 하면
yarn dev(프론트엔드 서버) 프로그램 자체에서 html, css, js를 브라우저에 전달하기 전에 소스코드를 먼저 돌려본다.

 

사전에 먼저 한 번 그려본다고 해서 프리렌더링이라고 한다.
말그대로 프리렌더링이기 때문에, 이때 모든 것을 완벽하게 그리는 것은 아니고 전체적인 구조만 그려둔다.
(useEffect 같은 mount 되고 나서 실행되는 것들은 빼고! onClick, onChange 등의 바인딩도 빠져있다.)

 

(2) hydration

프리렌더링 이후에 html, css, js를 브라우저로 보내주면 브라우저에서 제대로 그림을 그리고, 여기서 그린 그림과 프리렌더링할 때 그린 그림을 비교해서(diffing) 최종 완성형을 업데이트해준다.

diffing 이후 최종 완성형으로 업데이트될 때 onClick, onChange 등이 반영되는 것이다.

 

이렇게 diffing 이후에 최종 완성형으로 업데이트해주는 과정을 hydration이라고 한다.
(hydration: onClick 등이 빠져있는 정적인 데이터에 물기를 줘서 움직일 수 있게 해 준다는 의미)

 

Local Storage, Session Storage 등은 브라우저에 있는 것이다.
프리렌더링을 할 때는 (프론트엔드 서버에는) Local Storage라는 개념이 없다.

 

즉, 프론트엔드 서버에서 yarn dev해서 실행될 때(Pre-rendering)는
Local Storage라는 개념이 없어서 위에서 localStroage를 찾을 수 없다는 에러가 나온 것이다.

 

Pre-rendering 확인하기

아래 코드에서 window는 브라우저를 의미한다.
이 코드가 브라우저에서 실행될 경우에만 window가 존재한다.

  if(typeof window !== "undefined") {// 브라우저에서 실행되고 있을 때를 의미한다.
    console.log("여기는 브라우저다!")
  } else{ // 브라우저가 아닌 프론트엔드 서버에서 실행될 때를 의미한다.
    console.log("여기는 프론트엔드 서버이다!(yarn dev)")
  }

 

vsc 콘솔에는 프론트엔드가, 브라우저 콘솔에는 브라우저가 출력되어 나온다.

vsc console

browser console

 

(3) 해결 방법:

localStorage가 Pre-rendering에서 실행되지 않도록 막는다.

  useEffect(() => {
    const myLocalStorageAccessToken = localStorage.getItem("accessToken");
    setAccessToken(myLocalStorageAccessToken || "");
  }, []);

프리렌더링 당시 실행될 때만 문제가 되는 것이기 때문에
브라우저에서 실행될 때 localStorage.getItem을 하면 문제가 없다.

 

프리렌더링 때는 useEffect의 내용은 실행하지 않으므로,
useEffect에서 DOM이 Mount 되는 시점에 Local Storage에 접근해보자!!!
(프리렌더링 때는 마운트 전까지만 그린다.)

 

useEffect 말고 다른 방법들

 /* 첫번째 방법 -> deprecated */
   if (process.browser) {
     // 브라우저
   } else {
     // 프론트엔드 서버
   }

/* 두번째 방법 */
  if (typeof window !== "undefined") {
    // 브라우저
  } else {
    // 프론트엔드 서버
  }

/* 세번째 방법 */
  useEffect(() => {
    // 브라우저
  }, []);
728x90
반응형