11 November, 2024
Ah, the dreaded "window is not defined" error - the classic "gotcha" moment that every Next.js developer encounters sooner or later. If you're building content-rich websites with Next.js, you'll probably run into this error when accessing browser-specific APIs.
Let's break down why this happens and how to fix it, shall we?
Here's the thing: Next.js does something pretty cool - it pre-renders your pages on the server. This gives you better performance and SEO benefits (which we love!). But there's a catch: when your code runs on the server, there's no browser environment, which means no window
object.
It's like trying to use a swimming pool in winter before it's filled with water. The pool (your code) exists, but the water (the browser environment) isn't there yet!
The most straightforward way to handle this is to wait until your code runs in the browser. Here's how you can do it:
import { useEffect, useState } from 'react'
function MyComponent() {
const [windowWidth, setWindowWidth] = useState(undefined)
useEffect(() => {
// Now we're safely in the browser!
setWindowWidth(window.innerWidth)
}, [])
return <div>Window width is: {windowWidth}</div>
}
This works because useEffect
only runs after the component mounts in the browser. Pretty neat, right?
Sometimes, you might use a third-party library depending on the window object. In these cases, you can use dynamic imports:
import dynamic from 'next/dynamic'
const MyComponentWithNoSSR = dynamic(
() => import('../components/MyComponent'),
{ ssr: false }
)
This tells Next.js, "Hey, don't even try to render this on the server - wait for the browser!" It's like putting a "Do not open until Christmas" tag on your code. 😄
If you find yourself doing this often, you might want to create a custom hook. Here's one we use frequently when building content management solutions:
function useHasMounted() {
const [hasMounted, setHasMounted] = useState(false)
useEffect(() => {
setHasMounted(true)
}, [])
return hasMounted
}
Now you can easily check if your code is running in the browser:
function MyComponent() {
const hasMounted = useHasMounted()
if (!hasMounted) {
return null // or a loading state
}
return <div>I'm only rendered in the browser!</div>
}
When building content-heavy applications, here are some tips to avoid this error:
getInitialProps
or getServerSideProps
)Remember, the goal is to create a smooth experience for your content creators and readers alike. Sometimes that means being a bit clever about how we handle these browser-specific scenarios.
The next time you see "window is not defined," don't panic! Just remember that your code is trying to swim before the pool is filled. Give it the proper environment it needs, and you'll be back to building awesome content-driven experiences in no time.
Happy coding! 🚀