How to solve "window is not defined" errors in React and Next.js
Tags: javascript, nextjs, errors, debugging
Published: 2020-06-10 11:16:03

---
title: How to solve "window is not defined" errors in React and Next.js
published: true
description: 
tags: javascript,nextjs,error,debugging
---

Next.js is a React framework with [pre-rendering](https://nextjs.org/docs/basic-features/pages#pre-rendering) abilities. This means that for every page, Next.js will try to generate the HTML of the page for better SEO and performance.

This is why, if you're trying to do this:

```js
// components/Scroll.js
window.addEventListener("scroll", function() {
  console.log("scroll!")
});
```

Then it will fail with "ReferenceError: window is not defined":

![React error](https://dev-to-uploads.s3.amazonaws.com/i/yv6c87jzvxn9229x1ybt.png)

Because in the Node.js world, window is not defined, window is only available in browsers.

There are three ways to solve that:

## 1. First solution: typeof

While you can't use:

```js
if (window !== undefined) {
  // browser code
}
```

Because this would try to compare a non-existent variable (window) to undefined, resulting in the mighty "ReferenceError: window is not defined". You can still use:

```js
if (typeof window !== "undefined") {
  // browser code
}
```

Because typeof won't try to evaluate "window", it will only try to get its type, in our case in Node.js: "undefined".

PS: Thanks to [
Rogier Nitschelm](https://dev.to/teamroggers) for reminding me about this. I initially tried to do `if (typeof window !== undefined)` and this failed hard because of the reasons mentioned earlier.

The other solutions below are more exotic but still worth it.

## 2. Second solution: the useEffect hook

The "React" way to solve this issue would be to use the [useEffect](https://reactjs.org/docs/hooks-effect.html) React hook. Which only runs at the rendering phase, so it won't run on the server.

Let's update our scroll.js component:

```js
// components/Scroll.js

import React, { useEffect } from "react";

export default function Scroll() {
  useEffect(function mount() {
    function onScroll() {
      console.log("scroll!");
    }

    window.addEventListener("scroll", onScroll);

    return function unMount() {
      window.removeEventListener("scroll", onScroll);
    };
  });

  return null;
}
```

What we've done here is to turn our initial JavaScript file into a true React component that then needs to be added to your React tree via:

```js
// pages/index.js

import Scroll from "../components/Scroll";

export default function Home() {
  return (
    <div style={{ minHeight: "1000px" }}>
      <h1>Home</h1>
      <Scroll />
    </div>
  );
}
```

**Tip:** The way we use useEffect in the example is to register and unregister the listeners on mount/unmount. But you could also just register on mount and ignore any other rendering event, to do so you would do this:

```js
// components/Scroll.js

import React, { useEffect } from "react";

export default function Scroll() {
  useEffect(function onFirstMount() {
    function onScroll() {
      console.log("scroll!");
    }

    window.addEventListener("scroll", onScroll);
  }, []); // empty dependencies array means "run this once on first mount"

  return null;
}
```

## 3. Third solution: dynamic loading

A different solution is to load your Scroll component using [dynamic imports](https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr) and the `srr: false` option. This way your component won't even be rendered on the server-side at all.

**This solution works particularly well when you're importing external modules depending on `window`.** (Thanks [Justin](https://twitter.com/jmsunseri)!)

```js
// components/Scroll.js

function onScroll() {
  console.log("scroll!");
}

window.addEventListener("scroll", onScroll);

export default function Scroll() {
  return null;
}
```

```js
// pages/index.js

import dynamic from "next/dynamic";

const Scroll = dynamic(
  () => {
    return import("../components/Scroll");
  },
  { ssr: false }
);

export default function Home() {
  return (
    <div style={{ minHeight: "1000px" }}>
      <h1>Home</h1>
      <Scroll />
    </div>
  );
}
```

If you do not need the features of useEffect, you can even remove its usage completely as shown here.

**Finally**, you could also load your `Scroll` component only in [_app.js](https://nextjs.org/docs/advanced-features/custom-app) if what you're trying to achieve is to globally load a component and forget about it (no more mount/unmount on page change).

I have used this technique to display a top level progress bar with [NProgress](https://github.com/rstacruz/nprogress) in this article: {% link https://dev.to/vvo/show-a-top-progress-bar-on-fetch-and-router-events-in-next-js-4df3 %}