Хорошо, я разобрался в своей проблеме. Проблема в том, что хук useMouseMove()
обновлял координаты с помощью useState , когда я действительно хотел использовать useRef , что позволило мне обязательно"изменить ребенкавне типичного потока данных ", как уже упоминалось здесь .
Сначала я объединил useMouseMove()
ловушку с более общим useEventListener , поэтому мне не пришлосьперейти к ненужным абстракциям:
// a function that keeps track of mouse coordinates with useState()
export const useMouseMove = () => {
function getCoords(clientX,clientY) {
return {
x: clientX || 0,
y: clientY || 0
};
}
const [coords, setCoords] = useState(getCoords);
useEffect(
() => {
function handleMove(e) {
setCoords(getCoords(e.clientX,e.clientY));
}
global.addEventListener('mousemove', handleMove);
return () => {
global.removeEventListener('mousemove', handleMove);
};
}
);
return coords;
};
Следующим шагом было «преобразование» вышеуказанной функции из useState()
в useRef()
:
// a function that keeps track of mouse coordinates with useRef()
export const useMouseMove = () => {
function getCoords(clientX,clientY) {
return {
x: clientX || 0,
y: clientY || 0
};
}
const coords = useRef(getCoords); // ref not state!
useEffect(
() => {
function handleMove(e) {
coords.current = getCoords(e.clientX,e.clientY);
}
global.addEventListener('mousemove', handleMove);
return () => {
global.removeEventListener('mousemove', handleMove);
};
}
);
return coords;
};
Наконец, я могу получить доступ к координатам мышивнутри цикла анимации, сохраняя при этом пустой массив зависимостей, предотвращая повторную установку компонента анимации при каждом перемещении мыши.
// the animation loop that mounts only once with mouse coordinates
export const Canvas = () => {
let ref = React.useRef();
// custom hook that returns mouse position
const coords = useMouseMove();
React.useEffect(() => {
let canvas = ref.current;
let context = canvas.getContext('2d');
const render = () => {
aId = requestAnimationFrame(render);
drawNow(context,coords.current); // mouse coordinates from useRef()
};
let aId = requestAnimationFrame(render);
return () => cancelAnimationFrame(aId);
}, []); // dependancy array is blank, the animation loop mounts only once
return (
<canvas ref={ref}/>
style={{
width: '100%',
height: '100%',
}}
);
};
Благодаря этому escape-люку я могу создавать бесконечные веб-развлечения без перемонтированияцикл анимации.