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
windowobject (or other global objects such asdocument) directly in your code. This is becausegatsby developis rendered by the browser, where there's awindowobject, howevergatsby buildoccurs 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
windowobject. In your case, you need to make it when the DOM tree is loaded (useEffectwith 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.