Доступ к значениям из eventListener внутри React Hook с пустым массивом зависимостей - PullRequest
0 голосов
/ 30 октября 2019

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

Размещение пустого массива зависимостей в анимационном хуке предотвращает его размонтирование и перемонтирование цикла анимации при каждом перемещении мыши, так какупоминается в этом руководстве и предлагается в примечании в React docs .

Так что приведенный ниже код работает, так как я могу получить доступ к coords внутри drawNow() функция, но монтирование и размонтирование цикла анимации каждый раз, когда мышь движется, не кажется приемлемым способом выполнения действий.

Как получить доступ к слушателям событий внутри ловушек React, которые намеренно установлены так, чтобы не зависеть?

Вот анимация и функция рисования ....

const drawNow = (context,coords) => {
    context.fillStyle = '#fff';
    context.beginPath();
    context.arc(coords.x,coords.y,50,0,2*Math.PI); // need coords here
    context.fill();
}

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); // requires current mouse coordinates
        };

        let aId = requestAnimationFrame(render);
        return () => cancelAnimationFrame(aId);
    }, [coords]); // dependancy array should be left blank so requestAnimationFrame mounts only once?

    return (
        <canvas ref={ref}/>
        style={{
            width: '100%',
            height: '100%',
        }}
    );
};

Вот пользовательский хук для координат мыши (ссылается на это useEventListener )

export const useMouseMove = () => {

    function getCoords(clientX,clientY) {
        return {
            x: clientX || 0,
            y: clientY || 0
        };
    }

    const [coords, setCoords] = useState(getCoords);

    useEventListener('mousemove', ({ clientX, clientY }) => {
        setCoords(getCoords(clientX,clientY));
    });
    return coords;
};

Спасибо и с нетерпением ждем возможности больше узнать о хуках и слушателях событий.

Ответы [ 2 ]

0 голосов
/ 31 октября 2019

Хорошо, я разобрался в своей проблеме. Проблема в том, что хук 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-люку я могу создавать бесконечные веб-развлечения без перемонтированияцикл анимации.

0 голосов
/ 30 октября 2019

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

Проверьте этот ответ, чтобы узнать, как это сделать: получение координат мышив React и JQuery

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