Цель : я хочу определить свою функцию animation () вне моей ловушки React useEffect () (которая загружает изображение для анимации), потому что я хочу определить его только один раз, а не каждый раз при зависимости меняется.
Проблема : Несмотря на то, что я вызываю функцию animation () в правильной области img (в img.onload), произойдет сбой, если я объявлю функцию вне области img. Кроме того, если я передаю параметр img
в определение анимации (img), он также не работает, что для меня не имеет никакого смысла.
Почему это сбивает с толку : я никогда прежде не видел сценария, где определение функции должно быть объявлено в области видимости ее параметров. Обычно требуется только вызвать в области действия параметра. Я также никогда не видел функцию, которая дает сбой при объявлении параметра в определении.
Код, который делает то, что я ожидаю (вроде)
, чтобы воспроизвести эту проблему, создать приложение create-реагировать, а затем заменить файл "/ src / Приложение. js "с этим кодом.
Этот компонент работает, потому что функция animation () определена внутри области img в хуке useEffect (), а img не передается в качестве параметра. (т.е. function animation () {}; не function animation (img) {}).
перетащите кружок на изображение, чтобы использовать приложение
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;
Я не знаю, почему я должен определить animation () внутри хука useEffect. Кроме того, приложение перестает работать, если я включаю в параметр 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
Резюме : функция анимации моего приложения сильно выросла, со многими параметрами и зависимостями. Мне нужно устранять проблемы с процессором, и я хочу начать с объявления функции только один раз. Почему я не могу объявить определение функции вне области img.onload? Что такого особенного в параметре img, что он не работает, если я включаю его в определение функции? Я не знаю, как начать упрощать анимацию, если не могу переместить саму функцию.