React Hook 被有条件地调用 - Gatsby window undefined

React Hook is called conditionally - Gatsby window undefined

我有一个设置页眉高度的函数,这是使用 window 对象。因为我使用 Gatsby 作为我的 SSG,所以 window 在构建期间不可用。我有一个解决方法(在下面),但这会在 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>
  )
}

问题:如何在构建期间调整我的代码以获取和设置 headerheight,而不出现任何 window 未定义错误。

不能有条件地或在循环中调用挂钩。它们必须位于组件的顶层,并且始终以相同的顺序调用。

重构

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 windowSize = useWindowSize()
    const windowHeight = windowSize?.height; // May be null
    // set header height
    useEffect(() => {
      if (isBrowser) {
        document.body.style.setProperty("--vh", `${windowHeight * 0.01}px`)
      }
    }, [windowHeight])

将 React Hook 置于 if 语句之外的一种简单方法是传入您正在测试的数据(在本例中为 window)并直接在 Hook 内部测试它是否未定义。与 useEffect 一样,您必须在 Hooks 内部进行测试,而不是通过测试来决定是否必须使用 Hooks。