Реагировать на прослушивание дубликатов addEventListener

Я делаю приложение-галерею в React, и я застрял, потому что, когда я хочу изменить img с помощью клавиши (стрелка влево и вправо) React/browser/JS? дублирует прослушиватель, как вы можете видеть:

Код выглядит следующим образом:

const handleKey = (e) => {
        console.info(`user has pressed ${e.key}`);
        if (e.key === 'ArrowLeft') {
            previousPicture();
        }
        if (e.key === 'ArrowRight') {
            nextPicture();
        }
    };

    useEffect(() => {
        document.addEventListener('keydown', handleKey);
        return () => window.removeEventListener('keydown', handleKey);
    });

Я попытался:

Когда я пытался, например. это, приложение работало нормально, но нужно было нажать TAB, а затем использовать стрелки.

<Wrapper isOpen = {isOpen} tabIndex = {0} onKeyDown = {handleKey}>
// content...
</Wrapper>

Когда я перемещаюсь/меняю изображения кнопками, все работает хорошо.

Обновлено: Я изменил код и добавил useCallback (спасибо, добрый пользователь). «Повторяющаяся проблема» исчезла, но я не могу перемещаться со стрелками. Я пытался использовать в обратных вызовах nextPic/prevPic: [activeIndex], [] и без массива dep и все еще не работает.

Я создал песочницу: https://codesandbox.io/embed/dry-frog-tn86k2

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

kind user 18.11.2022 12:33

Определите handleKey внутри функции, которую вы используете для useEffect. В противном случае каждый раз при рендеринге компонента будет создаваться новый handleKey и window.removeEventListener('keydown', handleKey) не будет иметь никакого эффекта.

Titus 18.11.2022 12:37
Как использовать API парсинга квитанций с помощью JavaScript за 5 минут?
Как использовать API парсинга квитанций с помощью JavaScript за 5 минут?
В этом руководстве вы узнаете, как использовать API парсинга квитанций за 5 минут с помощью JavaScript. Eden AI предоставляет простой и удобный для...
Хук useOnClickOutside в ReactJS
Хук useOnClickOutside в ReactJS
Как разработчик ReactJS, вы, возможно, сталкивались с ситуацией, когда вам нужно закрыть модальное или выпадающее меню, когда кто-то щелкает за его...
Хуки (часть-2) - useEffect
Хуки (часть-2) - useEffect
Хук useEffect - один из самых мощных и универсальных инструментов в арсенале разработчика React. Он позволяет вам управлять побочными эффектами в...
Простое руководство по тестированию взаимодействия с пользователем с помощью библиотеки тестирования React
Простое руководство по тестированию взаимодействия с пользователем с помощью библиотеки тестирования React
В предыдущем посте я показал вам на примерах, как писать базовые тесты в React. Важнейшей частью пользовательского интерфейса приложений является...
Как конвертировать HTML в PDF с помощью jsPDF
Как конвертировать HTML в PDF с помощью jsPDF
В этой статье мы рассмотрим, как конвертировать HTML в PDF с помощью jsPDF. Здесь мы узнаем, как конвертировать HTML в PDF с помощью javascript.
Создайте титры как в звездных войнах с помощью CSS и Javascript
Создайте титры как в звездных войнах с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
1
2
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
использовать пустой массив зависимостей;

Если оставить массив зависимостей пустым, ожидаемого эффекта не будет, поскольку вам нужна ссылка на функцию-обработчик.

Вам придется обернуть функцию handleKey хуком useCallback, чтобы сохранить ссылку между рендерингами, поэтому очистка, которая происходит в useEffect, указывает на правильный экземпляр функции handleKey.

Примечание. Вероятно, вам также придется обернуть previousPicture и nextPicture useCallback. Зависит от того, как он инициализируется.

const handleKey = useCallback((e) => {
    console.info(`user has pressed ${e.key}`);
    if (e.key === 'ArrowLeft') {
        previousPicture();
    }
    if (e.key === 'ArrowRight') {
        nextPicture();
    }
}, []);

useEffect(() => {
    document.addEventListener('keydown', handleKey);
    return () => window.removeEventListener('keydown', handleKey);
}, [handleKey]);

Я прикрепил песочницу к своему вопросу.

lukaasz555 18.11.2022 13:42

@ lukaasz555 Работает отлично. Вы забыли только о зависимостях для функции handleKey. [previousPicture, nextPicture]

kind user 18.11.2022 13:50

Хахаха, ты прав! Большое спасибо за помощь! :)

lukaasz555 18.11.2022 13:59

Другие вопросы по теме