首页 > 解决方案 > gatsby + react hook masonry 在构建时中断,因为没有窗口

问题描述

我设置了一个反应挂钩来处理我的 gatsby 网站某些页面上的砌体。问题是它引用了服务器端不存在的窗口对象gatsby build我读过解决方案是将 useEffect 包装为

if (typeof window === 'undefined') {
}

但是我似乎无法包装我的砌体文件的正确部分。我还读到使用上述技巧会使服务器端渲染变得毫无意义,不确定。

有人可以告诉我 if 语句应该放在我下面的砌体文件中的什么位置吗?它不是一个插件,它是我的 utils 文件夹中的一个钩子。使用这个 tut 中的代码。我已经尝试了 useEffects 中的 if 语句,围绕 useEffects,围绕整个 eventListener,但没有骰子。谢谢!!

import React, { useEffect, useRef, useState } from "react"
import styled from "styled-components"

const useEventListener = (eventName, handler, element = window) => {
  const savedHandler = useRef()

  useEffect(() => {
    savedHandler.current = handler
  }, [handler])

  useEffect(() => {
    const isSupported = element && element.addEventListener
    if (!isSupported) return

    const eventListener = event => savedHandler.current(event)
    element.addEventListener(eventName, eventListener)

    return () => {
      element.removeEventListener(eventName, eventListener)
    }
  }, [eventName, element])
}

const fillCols = (children, cols) => {
  children.forEach((child, i) => cols[i % cols.length].push(child))
}

export default function Masonry({ children, gap, minWidth = 500, ...rest }) {
  const ref = useRef()
  const [numCols, setNumCols] = useState(3)
  const cols = [...Array(numCols)].map(() => [])
  fillCols(children, cols)

  const resizeHandler = () =>
    setNumCols(Math.ceil(ref.current.offsetWidth / minWidth))
  useEffect(resizeHandler, [])
  useEventListener(`resize`, resizeHandler)

  const MasonryDiv = styled.div`
    margin: 1rem auto;
    display: grid;
    grid-auto-flow: column;
    grid-gap: 1rem;
  `
  const Col = styled.div`
    display: grid;
    grid-gap: 1rem;
  `

  return (
    <MasonryDiv ref={ref} gap={gap} {...rest}>
      {[...Array(numCols)].map((_, index) => (
        <Col key={index} gap={gap}>
          {cols[index]}
        </Col>
      ))}
    </MasonryDiv>
  )
}

标签: reactjswindowreact-hooksgatsby

解决方案


在您gatsby-node.js添加以下代码段:

exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
  if (stage === "build-html") {
    actions.setWebpackConfig({
      module: {
        rules: [
          {
            test: /masonry/,
            use: loaders.null(),
          },
        ],
      },
    })
  }
}

注意:/masonry/使用node_modules.

来自有关调试 HTML 构建的 Gatsby 文档:

构建静态 HTML 文件时出现错误通常是由于以下原因之一:

您的一些代码引用了“浏览器全局变量”,例如窗口或文档。如果这是您的问题,您应该会看到上面的错误,例如“<code>window is not defined”。要解决此问题,请找到有问题的代码,然后 a) 在调用代码之前检查是否定义了窗口,因此代码在 Gatsby 构建时不会运行(请参见下面的代码示例)或 b) 如果代码在渲染函数中一个 React.js 组件,将该代码移动到componentDidMount生命周期或useEffect钩子中,以确保代码不会运行,除非它在浏览器中。

或者,您可以将导入的 Masonry 钩子用法包装在此语句中:

if (typeof window !== `undefined`) {
  const module = require("module")
}

请注意!==比较,而不是===您提供的比较。


推荐阅读