Search code examples
javascriptwebpackwebpack-hmr

Cannot remove listener on Hot Module Replacement


I am registering a handler (for click event). Before registering the handler, I clear the same handler so as not to register two same handlers.

I am using Webpack's Hot Module Replacement. Every time I change something in the JavaScript source code, part of code registering the handler is rerun.

However, the handler is never removed.

export default class TaskHandlers {
    // Called from index.js
    registerAddTaskClick(addTaskElementId) {
        let element = document.querySelector(`#${addTaskElementId}`);
        if (element !== null) {
            // Never clears the handler
            element.removeEventListener('click', this.handleAddTaskClick);
            // Keeps piling on new handlers on every HMR.
            element.addEventListener('click', this.handleAddTaskClick);
        }
    }

    handleAddTaskClick(event) {
        console.log('Clicked');
    }
}

If I run element.removeEventListener() manually, only the last handler gets removed.


Solution

  • Save the reference to the function so that you remove the same function you're adding, you'll also need to .bind(this).

    export default class TaskHandlers {
        constructor() {
            this.element = document.querySelector(`#${addTaskElementId}`);
            this.handleAddTaskClick = this.handleAddTaskClick.bind(this);
        }
    
        // Called from index.js
        registerAddTaskClick(addTaskElementId) {
            if (this.element !== null) {
                this.element.addEventListener('click', this.handleAddTaskClick);
            }
        }
    
        handleAddTaskClick(event) {
            this.element.removeEventListener('click', this.handleAddTaskClick);
            console.log('Clicked');
        }
    }
    

    Update: Also remove the element when you click it and not before, so that you know that it already has a listener binded.

    A solution that might work (if it's really needed to keep the instance after changing the code with HMR) is to save the handler in the window object or a global variable that is not part of the module that's refreshed, it's not ideal but might do the trick for you since it's an exceptional case.