javascript - Vindue er ikke definert i Next.js React-app


I min Next.js-app ser det ut til at jeg ikke får tilgang til window:

Ubehandlet avvisning (ReferenceError): window er ikke definert

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

Svar #1

Men process-objektet har blitt utdatert i Webpack5 og også NextJS, fordi det er en NodeJS-variabel kun for backend-siden.

Så vi må bruke tilbake window-objektet fra nettleseren.

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

En annen løsning er å bruke en React-hook for å erstatte componentDidMount:

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

Svar #2

Hvis du bruker React Hooks kan du flytte koden inn i Effect Hook:

import * as React from "react";

export const MyComp = () => {

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

  return (<div></div>)
}

Koden inne i useEffect kjøres kun på klienten (i nettleseren), dermed har den tilgang til window.

Svar #3

Flytt koden fra componentWillMount() til componentDidMount():

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

I Next.js blir componentDidMount() kun kjørt på klienten hvor window og andre nettspesifikke API-er vil være tilgjengelige. Fra Next.js-wikien:

Next.js er universelt, noe som betyr at det kjører kode først på serversiden, deretter på klientsiden. Vindusobjektet er kun til stede på klientsiden, så hvis du absolutt trenger tilgang til det i en React-komponent, bør du legge den koden i componentDidMount. Denne livssyklusmetoden vil kun bli utført på klienten. Du kan også sjekke om det finnes et alternativt universelt bibliotek som kan passe dine behov.

I samme retning vil componentWillMount() bli avviklet i versjon 17 av React, så det vil i praksis kunne være potensielt usikkert å bruke i nær fremtid.

Svar #4

Uten 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

Svar #5

Feilen oppstår fordi window ennå ikke er tilgjengelig, mens komponenten fortsatt monteres. Du kan få tilgang til window-objektet etter at komponenten er montert.

Du kan lage en veldig nyttig hook for å få dynamisk window.innerHeight eller 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 

Brukstilfelle:

const [width, height] = useDeviceSize();

Svar #6

global?.window && window.innerHeight

Det er viktig å bruke operatoren ?., ellers kan byggekommandoen krasje.

Svar #7

componentWillMount() livssyklus-hook fungerer både på server- og klientsiden. I ditt tilfelle ville ikke serveren vite om window eller document under sideserving, forslaget er å flytte koden til enten

Løsning 1:

componentDidMount()

Eller, Løsning 2

I tilfelle det er noe du bare vil utføre i, kunne du skrevet noe som:

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

Svar #8

Litt sent, men du kan også vurdere å bruke Dynamiske Importer fra next for å slå av SSR for den komponenten.

Du kan pakke importen for komponenten din inne i en dynamisk funksjon, og deretter bruke den returnerte verdien som den faktiske komponenten.

import dynamic from 'next/dynamic'

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

<>
   <BoardDynamic />
</>

Svar #9

Beste løsningen noensinne

import dynamic from 'next/dynamic';

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

Svar #10

I konstruktøren til klassen din Component kan du legge til

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

Eksempel :

import React, { Component } from 'react'

class MyClassName extends Component {

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

Dette vil unngå feilen (i mitt tilfelle ville feilen oppstå etter at jeg klikket på oppdater siden).

Svar #11

Jeg må få tilgang til hashen fra URL-en, så jeg kommer opp med dette

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

Relaterte artikler