在参数'img'范围之外定义函数animate()失败,使用react useEffect

问题描述 投票:0回答:1

Goal:我想在我的React useEffect()钩子(用于加载动画图像)之外定义我的animation()函数,因为我只想定义一次,而不是每次依赖项都改变一次。

问题:即使我在正确的img范围(在img.onload中)调用animation()函数,但是如果我在img范围之外声明该函数,它也会失败。另外,如果我将参数img传递到定义animation(img)中,它也会失败,这对我来说没有任何意义。

为什么会造成混淆:我之前从未见过需要在其参数范围内声明函数定义的情况。通常只需要在参数范围内invoked。我也从未见过通过在定义中声明参数而失败的函数。

符合我期望的代码(种类)

要复制此问题,请创建一个create-react-app,然后用此代码替换文件“ /src/App.js”。

该组件起作用,因为animation()函数是在useEffect()挂钩中的img范围内定义的,并且img不作为参数传递。(即,函数animation(){};不是函数animation(img){})。

将圆圈拖到图像上以使用App

import React, { useRef, useEffect, useState } from "react";
import "./App.css";

function App() {
  const [mouseCoords, setMouseCoords] = useState({ x: 10, y: 10 });
  const mouseRef = useRef({
    down: false
  });
  const canvasRef = useRef();
  const animRef = useRef();

  useEffect(() => {
    var img = new Image();
    img.onload = () => {
      animation(); // || animation(img) .. invoking with img param is OK
    };
    img.src =
      "https://cdn-images-1.medium.com/max/1600/1*g6s1lvpfArJGorALkKNhvw.png";

    function animation() { // != animation(img) ..defining with img param throws error why??
      var canvas = canvasRef.current;
      var ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(img, 0, 0);
      ctx.beginPath();
      ctx.arc(mouseCoords.x, mouseCoords.y, 10, 0, 2 * Math.PI, false);
      ctx.fill();
      animRef.current = requestAnimationFrame(animation);
    }

    return cancelAnimationFrame(animRef.current);
  }, [mouseCoords]);

  function getCanvasCoord(canvas, x, y) {
    var rect = canvas.getBoundingClientRect();
    return {
      x: Math.round((x - rect.left) * (canvas.width / rect.width)),
      y: Math.round((y - rect.top) * (canvas.height / rect.height))
    };
  }

  const handleMouseDown = e => {
    mouseRef.current.down = true;
  };
  const handleMouseMove = e => {
    var { x, y } = getCanvasCoord(canvasRef.current, e.clientX, e.clientY);
    if (mouseRef.current.down) {
      setMouseCoords({ x, y });
    }
  };
  const handleMouseUp = e => {
    mouseRef.current.down = false;
  };

  return (
    <div className="App">
      <canvas
        ref={canvasRef}
        onMouseMove={handleMouseMove}
        onMouseDown={handleMouseDown}
        onMouseUp={handleMouseUp}
        width={500}
        height={500}
      ></canvas>
    </div>
  );
}

export default App;



我不知道为什么必须在useEffect挂钩内定义animation()。此外,如果我将其包含在img参数中,则该应用程序将失败

失败代码示例1

useEffect(() => {
    var img = new Image();
    img.onload = () => {
      animation(img); // animation(img) .. adding img param here is OK
    };
    img.src =
      "https://cdn-images-1.medium.com/max/1600/1*g6s1lvpfArJGorALkKNhvw.png";

    function animation(img) { //  animation(img) ..adding parameter to definition throws error why??
      var canvas = canvasRef.current;
      var ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(img, 0, 0);
      ctx.beginPath();
      ctx.arc(mouseCoords.x, mouseCoords.y, 10, 0, 2 * Math.PI, false);
      ctx.fill();
      animRef.current = requestAnimationFrame(animation);
    }


失败代码示例2

失败的另一种方法是尝试在useEffect挂钩之外声明动画功能。


  useEffect(() => {
    var img = new Image();
    img.onload = () => {
      animation(img);
    };
    img.src =
      "https://cdn-images-1.medium.com/max/1600/1*g6s1lvpfArJGorALkKNhvw.png";

    return cancelAnimationFrame(animRef.current);
  }, [mouseCoords]);

  function animation(img) {
    var canvas = canvasRef.current;
    var ctx = canvas.getContext("2d");
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(img, 0, 0);
    ctx.beginPath();
    ctx.arc(mouseCoords.x, mouseCoords.y, 10, 0, 2 * Math.PI, false);
    ctx.fill();
    animRef.current = requestAnimationFrame(animation);
  }

TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or SVGImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'
animation
src/App.js:27
  24 | var canvas = canvasRef.current;
  25 | var ctx = canvas.getContext("2d");
  26 | ctx.clearRect(0, 0, canvas.width, canvas.height);
> 27 | ctx.drawImage(img, 0, 0);
     | ^  28 | ctx.beginPath();
  29 | ctx.arc(mouseCoords.x, mouseCoords.y, 10, 0, 2 * Math.PI, false);
  30 | ctx.fill();
View compiled

Summary:我的应用动画功能已经增长很多,具有许多参数和依赖项。我需要对CPU问题进行故障排除,并且我想先声明一次该功能。为什么不能在img.onload范围之外声明函数定义? img参数有什么特别之处,如果我将其包含在函数定义中会失败呢?如果我不能移动函数本身,我不知道如何开始简化动画负担。

reactjs image scope requestanimationframe
1个回答
1
投票

requestAnimationFrame确实将requestAnimationFrame参数传递给您的回调,因此在第二次迭代中,您尝试绘制number,而不是DOMHighResTimeStamp

Image
© www.soinside.com 2019 - 2024. All rights reserved.