Служба Gatsby - проблема с холстом при первоначальном рендеринге - PullRequest
1 голос
/ 11 июля 2020

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

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

Пожалуйста, как я могу решить эту проблему.

См. Код ниже:

const HomePage = () => {
  let canvas = useRef(null)
  const size = useWindowSize()
  const { currentTheme } = useGlobalStateContext()

  useEffect(() => {
    let renderingElement = canvas.current
    let drawingElement = renderingElement.cloneNode()

    let drawingCtx = drawingElement.getContext("2d")
    let renderingCtx = renderingElement.getContext("2d")

    let lastX
    let lastY

    let moving = false

    renderingCtx.globalCompositeOperation = "source-over"
    renderingCtx.fillStyle = currentTheme === "dark" ? "#000000" : "#ffffff"
    renderingCtx.fillRect(0, 0, size.width, size.height)

    renderingElement.addEventListener("mouseover", e => {
      moving = true
      lastX = e.pageX - renderingElement.offsetLeft
      lastY = e.pageY - renderingElement.offsetTop
    })

    renderingElement.addEventListener("mouseup", e => {
      moving = false
      lastX = e.pageX - renderingElement.offsetLeft
      lastY = e.pageY - renderingElement.offsetTop
    })

    renderingElement.addEventListener("mousemove", e => {
      if (moving) {
        drawingCtx.globalCompositeOperation = "source-over"
        renderingCtx.globalCompositeOperation = "destination-out"
        let currentX = e.pageX - renderingElement.offsetLeft
        let currentY = e.pageY - renderingElement.offsetTop
        drawingCtx.lineJoin = "round"
        drawingCtx.moveTo(lastX, lastY)
        drawingCtx.lineTo(currentX, currentY)
        drawingCtx.closePath()
        drawingCtx.lineWidth = 120
        drawingCtx.stroke()
        lastX = currentX
        lastY = currentY

        renderingCtx.drawImage(drawingElement, 0, 0)
      }
    })
  }, [currentTheme, size])

  return (
    <Container>
      <Video>
        <video
          height="100%"
          width="100%"
          loop
          autoPlay
          muted
          src={require("../assets/somevideo.mp4")}
        />
      </Video>
      <Canvas
        width={size.width}
        height={size.height}
        ref={canvas}
      />
    </Container>
  )
}

# useWindowSize. js

import { useState, useEffect } from "react"

export default function useWindowSize() {
  const hasWindow = typeof window !== "undefined"

  function getSize() {
    const width = hasWindow ? window.innerWidth : null
    const height = hasWindow ? window.innerHeight : null
    return {
      width,
      height,
    }
  }

  const [windowSize, setWindowSize] = useState(getSize())

  useEffect(() => {
    if (hasWindow) {
      function handleResize() {
        setWindowSize(getSize())
      }

      window.addEventListener("resize", handleResize)

      return () => window.removeEventListener("resize", handleResize)
    }
  }, [hasWindow])

  return windowSize
}

Ответы [ 2 ]

0 голосов
/ 14 июля 2020

Хорошо, значит, это проблема регидратации, когда у React и Gatsby возникают проблемы с сопоставлением данных, пришедших с сервера, с изменением, которое вы хотите сделать в клиенте.

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

Итак, я отредактировал свою индексную страницу следующим образом, и это устранило проблему для меня.

0 голосов
/ 12 июля 2020

Перехватчик useEffect не будет работать при рендеринге на стороне сервера. Я подозреваю, что useWindowSize также использует useEffect, поэтому ваш холст, вероятно, изначально нарисован с разрешением 0x0 пикселей. Когда React регидратируется, ваш обратный вызов useEffect в компоненте HomePage захватывает текущую ссылку для size (закрытие), которая будет чем-то вроде { width: 0, height: 0 }. Поскольку вы не объявили size как зависимость в вашем обратном вызове useEffect, вновь созданная функция не будет вызываться.

Чтобы исправить это, вам просто нужно добавить size в useEffect массив зависимостей.

Вы можете избежать этого в будущем, используя eslint-plugin-react-hooks с настройкой eslint.

...