74
votes

In my Next.js app I can't seem to access window:

Unhandled Rejection (ReferenceError): window is not defined

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

Enter image description here

9
Move the code to componentDidMount() which is only executed on the client where with window is available. Besides, componentWillMount() is being deprecated in v17https://github.com/zeit/next.js/wiki/FAQ#i-use-a-library-which-throws-window-is-undefinedAlexander Staroselsky

9 Answers

64
votes

Move the code from componentWillMount() to componentDidMount():

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

In Next.js, componentDidMount() is executed only on the client where window and other browser specific APIs will be available. From the Next.js wiki:

Next.js is universal, which means it executes code first server-side, then client-side. The window object is only present client-side, so if you absolutely need to have access to it in some React component, you should put that code in componentDidMount. This lifecycle method will only be executed on the client. You may also want to check if there isn't some alternative universal library which may suit your needs.

Along the same lines, componentWillMount() will be deprecated in v17 of React, so it effectively will be potentially unsafe to use in the very near future.

84
votes

Another solution is by using process.browser to just execute your command during rendering on the client side only.

if (process.browser) {
  // Client-side-only code
}
49
votes

If you use React Hooks you can move the code into the 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>)
}

The code inside useEffect is only executed on the client (in the browser), thus it has access to window.

40
votes

With No 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
10
votes

In the constructor of your class Component you can add

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

Example:

import React, { Component } from 'react'

class MyClassName extends Component {

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

This will avoid the error (in my case, the error would occur after I would click reload of the page).

9
votes

componentWillMount() lifecycle hook works both on server as well as client side. In your case server would not know about window or document during page serving, the suggestion is to move the code to either

Solution 1:

componentDidMount()

Or, Solution 2

In case it is something that you only want to perform in then you could write something like:

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

I have to access the hash from the URL so I come up with this

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

I was facing the same problem when i was developing a web application in next.js This fixed my problem, you have to refer to refer the window object in a life cycle method or a react Hook. For example lets say i want to create a store variable with redux and in this store i want to use a windows object i can do it as follows:

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

So basically, when you are working with window's object always use a hook to play around or componentDidMount() life cycle method

1
votes

For such cases, Next.js has Dynamic Import.

A module that includes a library that only works in the browser, it's suggested to use Dynamic Import. Refer