Window Is Not Defined in Next.Js React App

Window is not defined in Next.js React app

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.

Next.js: window is not defined

One of Next.js's key features is that it can render parts of your React application on the server or even at build time. While this can be helpful in improving your page's performance, the downside is that the server does not provide the all same APIs that your application would have access to in the browser. In this case, there is no global window object defined.

Unfortunately, searching the source code for apexcharts.js turns up many references to window: https://github.com/apexcharts/apexcharts.js/search?q=window. This also occurs in their React wrapper: https://github.com/apexcharts/react-apexcharts/blob/ecf67949df058e15db2bf244e8aa30d78fc8ee47/src/react-apexcharts.jsx#L5. While there doesn't seem to be a way to get apexcharts to avoid references to window, you can prevent Next.js from using the chart on the server. The simplest way to do that is to wrap any reference to the code with a check for whether window is defined, e.g.

<div className="mixed-chart">
{(typeof window !== 'undefined') &&
<Chart
options={this.state.options}
series={this.state.series}
type="bar"
width={500}
/>
}
</div>

With apexcharts, you will also need to do this for the component import because the import alone will trigger a reference to window as shown in that second link. In order to get around that problem you will need to use a dynamic import as opposed to the normal import you currently have: https://nextjs.org/docs/advanced-features/dynamic-import

import dynamic from 'next/dynamic'

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

Window is not defined in nextJS

Next.js is a server-side rendering framework which means the initial call to generate HTML from the server. At this point, window object, is only available on the client-side (not on the server-side).

To solve this problem, you need to check window object availability.

import Link from 'next/link';
import React, { useState, useEffect, useRef } from "react";

const Navbar = () => {

const isMobile = typeof window !== "undefined" && window.innerWidth <= 767.98
const [isMenuOpen, setIsMenuOpen] = useState(!isMobile);
const toggle = () => isMobile && setIsMenuOpen(!isMenuOpen);
const ref = useRef()

useEffect(() => {

if (isMobile) {
const checkIfClickedOutside = (e) => {
if (!ref.current?.contains(e.target)) {
setIsMenuOpen(false);
}
};

document.addEventListener("mousedown", checkIfClickedOutside);

return () => {
// Cleanup the event listener
document.removeEventListener("mousedown", checkIfClickedOutside);
};
}
}, []);

return (
<>
<header>

<nav>
<div className="nav">

<div className="nav-brand">
<Link href="/" className="text-black"><a>Website</a></Link>
</div>
<div ref={ref}>
<div className="toggle-icon" onClick={toggle}>
<i id="toggle-button" className={isMenuOpen ? 'fas fa-times' : 'fas fa-bars'} />
</div>
{isMenuOpen && (
<div className={isMenuOpen ? "nav-menu visible" : "nav-menu"}>
<ul className="main-menu">

<li><Link href="/" onClick={toggle}><a>Home</a></Link></li>
<li><Link href="/blog" onClick={toggle}><a>Blog</a></Link></li>
<li className="drp">
<p className="dropbtn">Find <i className="fa-solid fa-angle-down"></i></p>
<ul className="dropdown-content">
<li><Link href="/find/portable-keyboards" onClick={toggle}><a>Portable Keyboards</a></Link></li>
</ul>
</li>


</ul>

</div>
)}

</div>
</div>
</nav>

</header>

</>
)
}

export default Navbar;

Another way you can fix it is you can move that window logic into useEffect (or componentDidMount on a class-based component)

import Link from 'next/link';
import React, { useState, useEffect, useRef } from "react";

const Navbar = () => {

const [isMobile, setIsMobile] = useState(false); //the initial state depends on mobile-first or desktop-first strategy
const [isMenuOpen, setIsMenuOpen] = useState(true);
const toggle = () => isMobile && setIsMenuOpen(!isMenuOpen);
const ref = useRef()

useEffect(() => {
setIsMobile(window.innerWidth <= 767.98)
setIsMenuOpen(window.innerWidth > 767.98)
}, [])

useEffect(() => {

if (isMobile) {
const checkIfClickedOutside = (e) => {
if (!ref.current?.contains(e.target)) {
setIsMenuOpen(false);
}
};

document.addEventListener("mousedown", checkIfClickedOutside);

return () => {
// Cleanup the event listener
document.removeEventListener("mousedown", checkIfClickedOutside);
};
}
}, [isMobile]);

return (
<>
<header>

<nav>
<div className="nav">

<div className="nav-brand">
<Link href="/" className="text-black"><a>Website</a></Link>
</div>
<div ref={ref}>
<div className="toggle-icon" onClick={toggle}>
<i id="toggle-button" className={isMenuOpen ? 'fas fa-times' : 'fas fa-bars'} />
</div>
{isMenuOpen && (
<div className={isMenuOpen ? "nav-menu visible" : "nav-menu"}>
<ul className="main-menu">

<li><Link href="/" onClick={toggle}><a>Home</a></Link></li>
<li><Link href="/blog" onClick={toggle}><a>Blog</a></Link></li>
<li className="drp">
<p className="dropbtn">Find <i className="fa-solid fa-angle-down"></i></p>
<ul className="dropdown-content">
<li><Link href="/find/portable-keyboards" onClick={toggle}><a>Portable Keyboards</a></Link></li>
</ul>
</li>


</ul>

</div>
)}

</div>
</div>
</nav>

</header>

</>
)
}

export default Navbar;

Note that, with this solution, your UI may have some flickering due to isMobile state

Server Error ReferenceError: window is not defined in Next.js

This is because NextJS is trying to execute that function on the server because it uses SSR, and window is a browser object. Since the window object is available only in the browser (client-side), the server is unable to identify the window object, hence getting undefined. In order to fix this, you should make sure that any functions/components that contain client-side related code be executed only on the browser or client-side. One way is using hooks such as useEffect that run only after the component is mounted. Another way is to use lazy loading which pretty much does the same thing.

  1. Using useEffect hook.
    In your _app.tsx component, add a new useEffect hook and move the initialization code into the newly created useEffect function.
useEffect(()=>{
cleverTap.initialize('TEST-61c-a12');
},[])

  1. Using lazy loading. (Dynamic import)
    Instead of directly importing the function, import it dynamically and set server-side rendering to false:
import dynamic from 'next/dynamic'

const cleverTap = dynamic(()=>{
return import("utils/cleverTapHelper")
},
{ssr:false}
)

cleverTap.initialize('TEST-61c-a12');

ReferenceError: window is not defined in getServerSideProps for Next.js App And I Need to Store A Variable Persistantly in The getServerSideProps Func

You can persist the data in the cookies. You can do so from scratch with

res.header('set-cookie: key=value; max-age=2592000');

Add retrieve cookies from document.cookie. Or use a library like cookies-next.

import { setCookies, getCookie  } from 'cookies-next';

setCookies('key', 'value', options);
getCookie('key', options); // => 'value'


Related Topics



Leave a reply



Submit