Как избежать замыкания в колбеке в EventListener?

Из редюссера я получаю номер текущей песни.
Затем я создаю функцию, которая визуально ставит на паузу предыдущую песню.Этот колбек я создаю при каждом изменении номера песни ( так же я пробовал создавать его единожды, но и это не решало проблему).
Дальше я единожды среди всех рендеров вешаю событие 'ended'. В этом событие я вызываю колбек. Мне нужно, чтобы в колбеке был номер текущей песни, который меняется от рендера к рендеру.
Я испытал пару способов: пробовал вызвать колбек, передавая в него номер:

() => {listenerEnd(MusicPanel)}
Также я пробовал дать функции получать MusicPanel из окружения (код ниже), но и это не помогло. Во всех этих случаях колбек вызывался с изначально заложенным окружением.

//Мой текущий код(выбрал только нужные куски)
export const TopPanel = memo(() => {

const /*...*/ MusicPanel = UseSelectorMusic()/*Мой личный селектор, который получает музыку из редюссера*/;

    const listenerEnd = useCallback(() => {//Тот самый колбек
        try {
            if (MusicPanel.PlayingInSite) {
                console.log(MusicPanel.NumberOFSong);//Изначальное значение
                document.getElementById(`ButtonPauseOFSongInSite${MusicPanel.NumberOFSong - 1}`).style.display = "none";
                document.getElementById(`ButtonPlayOFSongInSite${MusicPanel.NumberOFSong - 1}`).style.display = "block";
            } else {
                document.getElementById(`ButtonPauseOFSongInPost${MusicPanel.NumberOFSong - 1}`).style.display = "none";// 
                document.getElementById(`ButtonPlayOFSongInPost${MusicPanel.NumberOFSong - 1}`).style.display = "block";
            }
            (document.getElementById("SongInSiteAudio") as HTMLAudioElement).src = MusicPanel.Dir;
            (document.getElementById("SongInSiteAudio") as HTMLAudioElement).play();

        } catch (e) {console.log(e)}
       /*...*/
    }, [MusicPanel.NumberOFSong]);

    useEffect( () => {
       /*...*/
        (document.getElementById("SongInSiteAudio") as HTMLAudioElement).addEventListener('ended',
            listenerEnd
        );
    }, []);

Я смог обойти это, передав в функцию useEffect MusicPanel в массив зависимостей. Это помогает, так как я пересоздаю колбек, но появляется новая проблема, а именно обработчиков событий становится в два раза больше после каждого рендера.
Тогда мой код становится похожим на это:

export const TopPanel = memo(() => {

const /*...*/ MusicPanel = UseSelectorMusic()/*Мой личный селектор, который получает музыку из редюссера*/;

    const listenerEnd = useCallback(() => {//Тот самый колбек
        try {
            if (MusicPanel.PlayingInSite) {
                console.log(MusicPanel.NumberOFSong);//Изначальное значение
                document.getElementById(`ButtonPauseOFSongInSite${MusicPanel.NumberOFSong - 1}`).style.display = "none";
                document.getElementById(`ButtonPlayOFSongInSite${MusicPanel.NumberOFSong - 1}`).style.display = "block";
            } else {
                document.getElementById(`ButtonPauseOFSongInPost${MusicPanel.NumberOFSong - 1}`).style.display = "none";// 
                document.getElementById(`ButtonPlayOFSongInPost${MusicPanel.NumberOFSong - 1}`).style.display = "block";
            }
            (document.getElementById("SongInSiteAudio") as HTMLAudioElement).src = MusicPanel.Dir;
            (document.getElementById("SongInSiteAudio") as HTMLAudioElement).play();

        } catch (e) {console.log(e)}
       /*...*/
    }, [MusicPanel.NumberOFSong]);

    useEffect( () => {
       /*...*/
        (document.getElementById("SongInSiteAudio") as HTMLAudioElement).addEventListener('ended',
            listenerEnd
        );
    }, [MusicPanel.NumberOfSong]);/*Теперь я пересоздаю слушатель событий, что раздваивает его после каждого рендера. В JS документации говорится, что при при повтором вызове слушателя событий прошлый затирается, но не в моём случаи, почему-то.*/

Как бы обойти это замыкание?
  • Вопрос задан
  • 113 просмотров
Решения вопроса 1
0xD34F
@0xD34F Куратор тега React
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы