My Boundary As Much As I Experienced

Next.js) window is not defined 오류 해결법 (Dynamic Import) 본문

FrontEnd/Next.js

Next.js) window is not defined 오류 해결법 (Dynamic Import)

Bumang 2024. 3. 1. 02:58

문제

Next.js 환경에서 window 객체에 접근해야되는 일이 생겼다. useInnerWidth하는 훅을 만들어서 resize 이벤트를 감지해서 위 gif 스티커들의 좌표와 크기를 반응형으로 조절해주는 기능을 구현하기 위해 필요했다.

그런데  Next.js 환경에선 window객체에 접근하면 referenceError: window is not defined라는 에러를 반환한다.

원인

Next.js에선 기본적으로 ssr로 페이지를 로딩하기 때문에 window 전역 객체가 브라우저를 뜻하지 않는다.

그러므로 구글에서 next.js의 window객체 접근 에러에 대해 찾아보면

흔히 'csr로 전환하기 위해서 "use client"를 해주면 해결된다.'라고 흔히 답을 찾을 수 있는데 이것만으로는 부족할 수 있다.

대표적인 해결방법

  1. "use client" 사용 후 useEffect에서 window 객체에 타입가드를 지정한다.
useEffect(() => {
  if (typeof window !== "undefined") {
    // window 객체를 사용하는 코드
  }
}, [])
  1. window 객체가 쓰이는 페이지/컴포넌트를 동적 로딩으로 가져온다. (lazy-loading 혹은 Dynamic loading이라 불린다.)

이렇게 하면 처음 ssr로 html을 로딩할 때 같이 로딩되지 않는다.
html이 다 로딩된 이후(DOMContentLoaded 이벤트 이후) 해당 컴포넌트를 클라이언트 사이드에서 후순위로 로딩하게 된다.

// next가 제공하는 dynamic 함수를 임포트 해준다.
import dynamic from 'next/dynamic';

// window객체에 접근하는 컴포넌트를 동적 로딩으로 가져와서 조립한다.
const Banner = dynamic(() => import('./_bannerComponents/banner'), {
  ssr: false
});

내 해결 방법

  1. window에 접근해야되는 컴포넌트 혹은 훅(내 경우엔 useInnerWidth)에 "use client"를 사용해준다.
  2. 동적 로딩으로 html이 로드된 이후 로드하도록 설정한다.
// next가 제공하는 dynamic 함수를 임포트 해준다.
import dynamic from 'next/dynamic';

// window객체에 접근하는 컴포넌트를 동적 로딩으로 가져와서 조립한다.
const Banner = dynamic(() => import('./_bannerComponents/banner'), {
  ssr: false
});

const BannerSection = () => {
  return (
    <main className="flex w-full flex-col items-center justify-center pt-16">
      <Banner />
    </main>
  );
};

export default BannerSection;

동적 로딩을 순서 보장 혹은 특정 로직 회피를 하기 위하여 써보는 것은 또 처음이라 재밌는 경험치를 얻은 것 같다.