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.innerHeightDet 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;
