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.
- Using
useEffect
hook.
In your_app.tsx
component, add a newuseEffect
hook and move the initialization code into the newly createduseEffect
function.
useEffect(()=>{
cleverTap.initialize('TEST-61c-a12');
},[])
- Using lazy loading. (Dynamic import)
Instead of directly importing the function, import it dynamically and set server-side rendering tofalse
:
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
Can You Have a JavaScript Hook Trigger After a Dom Element's Style Object Changes
How to Animate a Progressive Drawing of Svg Path
How to Inject CSS into Webpage Through Chrome Extension
Using Jquery to Know When @Font-Face Fonts Are Loaded
Better Way to Prevent Browser Caching of JavaScript Files
Read :Hover Pseudo Class with JavaScript
Setting Rounded Corners for Svg:Image
Jquery Animate() and Backgroundcolor
Performance of CSS Transitions VS. Js Animation Packages
Using JavaScript to Edit CSS Gradient
Vue.Js - Add Class to Clicked Button
How to Determine If a Variable Is 'Undefined' or 'Null'
How to Detect CSS3 Resize Events