I am having a function to set the header height and this is using the window object. Because I am using Gatsby as my SSG, window is not available during build. I had a workaround (down below), but this will give me two errors during gatsby develop
.
error React Hook "useWindowSize" is called conditionally. React Hooks must be called in the exact same order in every component render
error React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render
import * as React from "react"
//Library
import { useEffect, useState } from "react"
import { useStaticQuery, graphql } from "gatsby"
import loadable from "@loadable/component"
//Components
import { Header } from "./header"
import { SkipNavContent, SkipNavLink } from "./skip-nav"
import { Seo } from "./seo"
import Toast from "./toast"
// import Cookie from "./cookie"
//Utils
import { StoreContext } from "../context/store-context"
import { isBrowser, useWindowSize } from "../utils/helpers"
const CartSidebar = loadable(() => import("./cart/CartSidebar"))
const Newsletter = loadable(() => import("./newsletter"))
const Footer = loadable(() => import("./footer"))
export function Layout({ children }) {
const { loading, didJustAddToCart } = React.useContext(StoreContext)
const [showLazySections, setShowLazySections] = React.useState(false)
if (typeof window !== "undefined") {
const { height: windowHeight } = useWindowSize()
// set header height
useEffect(() => {
if (isBrowser) {
document.body.style.setProperty("--vh", `${windowHeight * 0.01}px`)
}
}, [windowHeight])
}
const [headerHeight, setHeaderHeight] = useState(null)
useEffect(() => {
setShowLazySections(true)
}, [])
return (
<div
style={headerHeight ? { "--headerHeight": `${headerHeight}px` } : null}
>
<SkipNavLink />
{/* <Cookie siteTitle={siteTitle} /> */}
<Seo />
<Header onSetup={({ height }) => setHeaderHeight(height)} />
<SkipNavContent>{children}</SkipNavContent>
{showLazySections && (
<>
<CartSidebar />
<Newsletter />
<Footer siteTitle={siteTitle} />
</>
)}
</div>
)
}
QUESTION: How can I adjust my code to get and set headerheight, during build, without any window undefined errors.
2
Answers
Hooks cannot be called conditionally, or in loops. They must be at the top level of the component and always called in the same order.
Refactor
to
A simple way to put the React Hook out of the if statement is to pass in the data you are testing (in this case the window) and test if it is undefined directly inside the Hook. Like with useEffect you gotta Test inside the Hooks and not Test to decide if you have to use the Hooks.