programing

Next.js React 앱에서 창이 정의되지 않았습니다.

kingscode 2023. 4. 1. 14:22
반응형

Next.js React 앱에서 창이 정의되지 않았습니다.

Next.js 앱에서 액세스할 수 없는 것 같습니다.window:

처리되지 않은 거부(ReferenceError): 창이 정의되지 않았습니다.

componentWillMount() {
    console.log('window.innerHeight', window.innerHeight);
}

여기에 이미지 설명을 입력하십시오.

'h''s's's's's''n't't's'l't's'l's's's's'i'i'n's's's'i's's'i's's'y's's's's's's's'i's's's's's's's's's's's's's's's's's's's's'sp̶r̶o̶c̶e̶s̶s̶.̶b̶r̶o̶w̶s̶e̶r'to' 'j'u' 'e' 'e' 'e' 'e' 'e' 'o' 'm' a n d' 'd' 'u' 'i ng' 'e' 'e' 'c' 'm' a

★★★★★★★★★★★★★★★★★.process'노드'JS Webpack 5 Next J스스 스 스 스스무리

다시 요.window오브젝트를 지정합니다.

if (typeof window !== "undefined") {
  // Client-side-only code
}

해결책은 훅을 하여 리액트 을 대체하는 입니다.componentDidMount:

useEffect(() => {
    // Client-side-only code
})

를 「」에서 이동합니다.componentWillMount()대상:

componentDidMount() {
  console.log('window.innerHeight', window.innerHeight);
}

Next.js의 componentDidMount()는, 「이행」이에서만 실행됩니다.window기타 브라우저 고유의 API를 이용할 수 있습니다.Next.js Wiki에서:

next.js는 범용입니다.즉, 먼저 서버측에서 코드를 실행하고 다음으로 클라이언트측에서 코드를 실행합니다.창 개체는 클라이언트 측에서만 존재하므로 일부 React 구성 요소에서 반드시 액세스할 수 있어야 하는 경우 componentDidMount에 해당 코드를 넣어야 합니다.이 라이프 사이클 메서드는 클라이언트에서만 실행됩니다.또한 필요에 맞는 대체 유니버설 라이브러리가 없는지 확인하는 것이 좋습니다.

행으로, 「 」는 「 」componentWillMount()React의 v17에서는 권장되지 않기 때문에 가까운 장래에 사용하는 것은 사실상 안전하지 않을 수 있습니다.

리액트 훅을 사용하면 코드를 이펙트 훅으로 이동할 수 있습니다.

import * as React from "react";

export const MyComp = () => {

  React.useEffect(() => {
    // window is accessible here.
    console.log("window.innerHeight", window.innerHeight);
  }, []);

  return (<div></div>)
}

「 」의 .useEffect는 클라이언트에서만 실행되므로 (브라우저)에 액세스 할 수 있습니다.window.

SSR 없음

https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr

import dynamic from 'next/dynamic'

const DynamicComponentWithNoSSR = dynamic(
  () => import('../components/hello3'),
  { ssr: false }
)

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponentWithNoSSR />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home

컴포넌트가 아직 마운트되어 있는 동안에는 창을 사용할 수 없기 때문에 오류가 발생.구성 요소가 마운트된 후 창 개체에 액세스할 수 있습니다.

다이나믹하게 하기 , 할 수 .window.innerHeight ★★★★★★★★★★★★★★★★★」window.innerWidth

const useDeviceSize = () => {

  const [width, setWidth] = useState(0)
  const [height, setHeight] = useState(0)

  const handleWindowResize = () => {
    setWidth(window.innerWidth);
    setHeight(window.innerHeight);
  }

  useEffect(() => {
    // component is mounted and window is available
    handleWindowResize();
    window.addEventListener('resize', handleWindowResize);
    // unsubscribe from the event on component unmount
    return () => window.removeEventListener('resize', handleWindowResize);
  }, []);

  return [width, height]

}

export default useDeviceSize 

사용 사례:

const [width, height] = useDeviceSize();

componentWillMount()라이프 사이클 훅은 서버측과 클라이언트측 모두에서 동작합니다. 수 있습니다.window ★★★★★★★★★★★★★★★★★」document서비스 .

해결책 1:

componentDidMount()

또는 솔루션 2

실행만 하고 싶은 경우 다음과 같이 쓸 수 있습니다.

componentWillMount() {
    if (typeof window !== 'undefined') {
        console.log('window.innerHeight', window.innerHeight);
    }
}

클래스 생성자에서 컴포넌트를 추가할 수 있습니다.

if (typeof window === 'undefined') {
    global.window = {}
}

예:

import React, { Component } from 'react'

class MyClassName extends Component {

    constructor(props){
        super(props)
        ...
        if (typeof window === 'undefined') {
            global.window = {}
        }
}

이렇게 하면 오류가 발생하지 않습니다(이 경우 페이지 새로고침을 클릭한 후에 오류가 발생합니다).

조금 늦었지만 다이내믹 Import를 사용하는 것도 검토해 주십시오.next끄다SSR그 컴포넌트에 대해서요.

동적 함수 내에서 컴포넌트의 Import를 워프한 후 반환된 값을 실제 컴포넌트로 사용할 수 있습니다.

import dynamic from 'next/dynamic'

const BoardDynamic = dynamic(() => import('../components/Board.tsx'), {
  ssr: false,
})

<>
   <BoardDynamic />
</>

global?.window && window.innerHeight

?.건축하다

URL에서 해시에 접속해야 하기 때문에, 이것을 생각해냅니다.

const hash = global.window && window.location.hash;

역대 최고의 솔루션

import dynamic from 'next/dynamic';

const Chart = dynamic(()=> import('react-apexcharts'), {
    ssr:false,
})

다음은 사용하기 쉬운 회피책입니다.

const runOnClient = (func: () => any) => {
  if (typeof window !== "undefined") {
    if (window.document.readyState == "loading") {
      window.addEventListener("load", func);
    } else {
      func();
    }
  }
};

사용방법:

runOnClient(() => {
// access window as you like
})

// or async
runOnClient(async () => {
// remember to catch errors that might be raised in promises, and use the `await` keyword wherever needed
})

그냥 .typeof window !== "undefined"창이 정의되어 있지 않은지 확인만 하면 페이지가 로 리다이렉트 되어도 동작하지 않고 로드 중에 한 번만 동작하기 때문입니다.다만, 이 회피책은, 로드중에 1 회만이 아니고, 페이지가 리다이렉트 된 경우에도 유효합니다.

next.js에서 어플리케이션을 개발할 때도 같은 문제에 직면해 있었습니다.이 때문에 문제가 해결되었습니다.라이프 사이클 방식이나 리액트 훅에서는 윈도 오브젝트를 참조해야 합니다.예를 들어 redux를 사용하여 스토어 변수를 만들고 이 스토어에서는 다음과 같이 Windows 개체를 사용할 수 있습니다.

let store
useEffect(()=>{
    store = createStore(rootReducers,   window.__REDUX_DEVTOOLS_EXTENSION__ && 
    window.__REDUX_DEVTOOLS_EXTENSION__())
 }, [])
 ....

할 때는 to to so so so so so so so so so so so so so so so so so so so so so so so so so so so 。componentDidMount()

용액을 했습니다.if (typeof window === 'undefined') return;커스텀 훅으로, 매우 만족하고 있습니다.은, 반응하는 있습니다.useMemo이치노

import { useEffect, useMemo, useState } from "react";

const InitialState = Symbol("initial");

/**
 *
 * @param clientFactory Factory function similiar to `useMemo`. However, this function is only ever called on the client and will transform any returned promises into their resolved values.
 * @param deps Factory function dependencies, just like in `useMemo`.
 * @param serverFactory Factory function that may be called server side. Unlike the `clientFactory` function a resulting `Promise` will not be resolved, and will continue to be returned while the `clientFactory` is pending.
 */
export function useClientSideMemo<T = any, K = T>(
  clientFactory: () => T | Promise<T>,
  deps: Parameters<typeof useMemo>["1"],
  serverFactory?: () => K
) {
  const [memoized, setMemoized] = useState<T | typeof InitialState>(
    InitialState
  );

  useEffect(() => {
    (async () => {
      setMemoized(await clientFactory());
    })();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, deps);

  return typeof window === "undefined" || memoized === InitialState
    ? serverFactory?.()
    : memoized;
}

사용 예:

next.js의 SSR와 호환되지 않는 라이브러리를 동적으로 가져오기 위해 사용합니다. 왜냐하면 동적 가져오기는 컴포넌트와만 호환되기 때문입니다.

  const renderer = useClientSideMemo(
    async () =>
      (await import("@/components/table/renderers/HighlightTextRenderer"))
        .HighlightTextRendererAlias,
    [],
    () => "text"
  );

보시는 바와 같이 폴백팩토리 콜백도 실장되어 있기 때문에 서버에서 처음 렌더링할 때도 결과를 제공할 수 있습니다. 모든 에서 이 는 반응과 하게 동작해야 .useMemo후크. 피드백에 개방적이야.

이러한 경우 Next.js에는 동적 가져오기가 있습니다.

브라우저에서만 작동하는 라이브러리를 포함하는 모듈입니다. 동적 가져오기를 사용하는 것이 좋습니다.참조

날짜: 2021년 6월 8일

window 객체가 존재하는지 확인한 후 코드를 따릅니다.

 function getSelectedAddress() {
    if (typeof window === 'undefined') return;

    // Some other logic
 }

Next.js 버전12.1.0의 경우,process.title 있는지 browser ★★★★★★★★★★★★로node움이이됐됐!

export default function Projects(props) {
    console.log({ 'process?.title': process?.title });

    return (
        <div></div>
    );
}

1. 단말기로부터 수신합니다.{ 'process?.title': 'node' }

process.syslog === '노드'

2. Chrome devtool에서 복습합니다.{ 'process?.title': 'browser' }

process.syslog === 'syslog'

페이지를 새로 고칠 때도 같은 문제가 발생했습니다(SSR에서 제대로 작동하지 않는 가져오기로 인해 발생).

이 문제를 해결한 것은 이 문제가 발생한 페이지로 이동하여 Import를 동적으로 강제하는 것이었습니다.

import dynamic from 'next/dynamic';


const SomeComponent = dynamic(()=>{return import('../Components/SomeComponent')}, {ssr: false});

//import SomeComponent from '../Components/SomeComponent'

컴포넌트의 원래 Import 및 Import를 코멘트 아웃하면 컴포넌트의 클라이언트 측 렌더링이 동적으로 실행됩니다.

동적 Import에 대해서는 다음 URL의 Nextjs 문서를 참조하십시오.https://nextjs.org/docs/advanced-features/dynamic-import

저는 이 해결책에 대해 여기 유튜브 비디오를 보고 알게 되었습니다.

상태 변수를 정의하고 창 이벤트 핸들을 사용하여 이와 같은 변경을 처리할 수 있습니다.

const [height, setHeight] = useState();

useEffect(() => {
    if (!height) setHeight(window.innerHeight - 140);
    window.addEventListener("resize", () => {
        setHeight(window.innerHeight - 140);
    });
}, []);

현재 경로 이름(CurrentUrl Path)얻기 위해 -와 같은 사용 사례에 대해 아래 코드 스니펫을 사용할 수 있습니다.

 import { useRouter } from "next/router";

 const navigator = useRouter()
 console.log(navigator.pathname);

후크를 사용할 수 없는 경우(예를 들어 기능 구성요소):

setTimeout(() => yourFunctionWithWindow());를 사용하면 윈도 인스턴스를 얻을 수 있습니다.로딩하는 데 시간이 좀 더 필요한 것 같아요.

저는 제가 흥미를 느낀 이 접근방식을 미래의 연구자들에게 남기고 싶습니다.커스텀 useEventListener를 사용하여 많은 다른 요구에서 사용할 수 있습니다.

여기서 제안하는 것처럼 원래 게시된 내용에 약간의 변경 사항을 적용해야 합니다.

이렇게 끝납니다.

import { useRef, useEffect } from 'react'

export const useEventListener = (eventName, handler, element) => {
  const savedHandler = useRef()

  useEffect(() => {
    savedHandler.current = handler
  }, [handler])

  useEffect(() => {
    element = !element ? window : element
    const isSupported = element && element.addEventListener
    if (!isSupported) return

    const eventListener = (event) => savedHandler.current(event)

    element.addEventListener(eventName, eventListener)

    return () => {
      element.removeEventListener(eventName, eventListener)
    }
  }, [eventName, element])
}

NextJS 앱과 _document.js 내부에 있는 경우 다음을 사용하십시오.

<script dangerouslySetInnerHTML={{
        __html: `
            var innerHeight = window.innerHeight;
        `
        }} />

언급URL : https://stackoverflow.com/questions/55151041/window-is-not-defined-in-next-js-react-app

반응형