I am new to gatsby and server side rendering, although I've worked with react quite a bit before. I wrote a bit of code that checks for the window size and then renders either the nav or the mobile nav based on the width. However, when I tried to test-deploy, I discovered that the window object is not available when you use server side rendering. My question is, is there any way i can modify my code to still work? or should I just rebuild everything with sass and media queries?
import React, { useState, useEffect } from "react"
import { Link, graphql, useStaticQuery } from "gatsby"
// import "./header.module.scss"
import HeaderStyles from "./header.module.scss"
import Logo from "../images/[email protected]"
import Nav from "./nav"
const Header = () => {
const data = useStaticQuery(graphql`
query MyQuery {
site {
siteMetadata {
title
}
}
}
`)
const [isDesktop, setDesktop] = useState(window.innerWidth > 768)
const updateMedia = () => {
setDesktop(window.innerWidth > 768)
}
useEffect(() => {
window.addEventListener("resize", updateMedia)
return () => window.removeEventListener("resize", updateMedia)
})
const [menuActive, setMenuState] = useState(false)
return (
<header
className={menuActive ? HeaderStyles.mobileNav : HeaderStyles.header}
>
<Link to="/" className={HeaderStyles.title}>
{/* {data.site.siteMetadata.title} */}
<img src={Logo} height="60" />
</Link>
{isDesktop ? (
<Nav />
) : (
//hamburger
<div
onClick={() => setMenuState(!menuActive)}
className={`${HeaderStyles.navIcon3} ${
menuActive ? HeaderStyles.open : ""
}`}
>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
)}
{menuActive ? <Nav /> : null}
</header>
)
}
export default Header
You can't use the
window
object (or other global objects such asdocument
) directly in your code. This is becausegatsby develop
is rendered by the browser, where there's awindow
object, howevergatsby build
occurs in the Node server (your machine or you build system) where's there's nowindow
.If you don't want to redo your code with SCSS and mediaqueries (preferred version and more native), you need to make a condition above every use of
window
object. In your case, you need to make it when the DOM tree is loaded (useEffect
with emptydeps
,[]
). Something like this should work:Keep in mind that this approach will create a small blink (a few
ms
) until the code knows what's thewindow
's with and, depending on your use-case, it may not work when resizing it, we should readapt a little bit the code to make it functional there.