gatsby + react hook кладка ломается при сборке из-за отсутствия окна - PullRequest
1 голос
/ 07 мая 2020

У меня есть обработчик реакции, настроенный для обработки каменной кладки на определенных страницах моего сайта gatsby. Проблема в том, что он ссылается на объект окна, который не существует на стороне сервера gatsby build. Я читал, что решение состоит в том, чтобы обернуть useEffect в :

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

, однако я просто не могу обернуть правую часть моего файла каменной кладки. Я также читал, что использование вышеупомянутого хака делает рендеринг на стороне сервера бессмысленным, не уверен.

Может ли кто-нибудь сказать мне, где этот оператор if должен go в моем файле каменной кладки ниже? Это не плагин, это крючок в моей папке utils. Используя код из этого урока . Я пробовал оператор if внутри useEffects, вокруг 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>
  )
}

1 Ответ

2 голосов
/ 07 мая 2020

В свой gatsby-node.js добавьте следующий фрагмент:

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

Примечание: используйте /masonry/ путь к библиотеке из вашего node_modules.

From Gatsby документация об отладке HTML сборок :

Ошибки при сборке файлов c HTML обычно возникают по одной из следующих причин:

Некоторые вашего кода ссылаются на «глобальные объекты браузера», такие как окно или документ. Если это ваша проблема, вы должны увидеть выше сообщение об ошибке типа «window не определено». Чтобы исправить это, найдите проблемный код и либо а) проверьте перед вызовом кода, определено ли окно, чтобы код не запускался во время сборки Гэтсби (см. Пример кода ниже), либо б) если код находится в функции рендеринга компонент React. js, переместите этот код в жизненный цикл componentDidMount или в ловушку useEffect, которая гарантирует, что код не запускается, если он не находится в браузере.

В качестве альтернативы, вы можете заключить свой импорт в использование хуков Masonry в этот оператор:

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

Обратите внимание на сравнение !==, а не ===, подобное тому, которое вы предоставили.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...