2

It appears the listeners are not removed here. Any idea how to fix this? I am guessing it is to do with the manner I "share" the listener and I'm using arrow functions (per recommendation here https://medium.freecodecamp.org/reactjs-pass-parameters-to-event-handlers-ca1f5c422b9)

Code:

import * as React from 'react';

export default class ITestComponent extends React.Component { 

  public render() {
    return (
      <div>

        <div 
          onMouseDown={this.handleMouseDown('horizontal')}
          draggable={false}
          style={{ border: '1px solid blue', padding:20 }}
        >
          Horizontal Drag Test
        </div>

        <div 
          onMouseDown={this.handleMouseDown('vertical')}
          draggable={false}
          style={{ border: '1px solid green', padding:20 }}
        >
          Vertical Drag Test
        </div>

      </div>
    );
  }

  private handleMouseDown = (eType:string) => (e:any) => {
    console.log('Add Event Listeners (handleMouseDown)', eType)
    window.addEventListener('mousemove', this.handleMouseMove(eType))
    window.addEventListener('mouseup', this.handleMouseUp(eType))
  }

  private handleMouseMove = (eType:string) => (e:MouseEvent) => {
    console.log(' - handleMouseMove', eType, e.clientY)
  };

  private handleMouseUp = (eType:string) => (e:MouseEvent) => {
    console.log('Remove Listeners (handleMouseUp)', eType)
    window.removeEventListener('mousemove', this.handleMouseMove(eType))
    window.removeEventListener('mouseup', this.handleMouseUp(eType));
  };

}

Console Output after clicking on "horzontal drag test" and dragging down (with mouse button depressed), the releasing mouse button, then dragging a little more..

Add Event Listeners (handleMouseDown) horizontal
 - handleMouseMove horizontal 61
 ...
 - handleMouseMove horizontal 220
 - handleMouseMove horizontal 221
Remove Listeners (handleMouseUp) horizontal
 - handleMouseMove horizontal 222
 - handleMouseMove horizontal 222
 - handleMouseMove horizontal 228
 ...

Question specifically is how to retain the concept of "reusing" the event handler for multiple purposes?

Note I'm not using an anonymous function here like in one of the suggested answers (Javascript removeEventListener not working)

Greg
  • 34,042
  • 79
  • 253
  • 454
  • 4
    `this.handleMouseMove(eType)` returns a new function every time you use it, so the reference of the function you remove is not the same as the one you add. – Tholle Dec 21 '18 at 08:33
  • Possible duplicate of [Javascript removeEventListener not working](https://stackoverflow.com/questions/10444077/javascript-removeeventlistener-not-working) – Patrick Hund Dec 21 '18 at 08:42
  • but I guess the question is given I want to be able to pass the parameter in (to share the event handler) then how is it possible to do this sharing, i.e. need a way to remove the handler? – Greg Dec 21 '18 at 08:47

1 Answers1

2

Even when you define you function with curried arrow functions and execute say this.handleMouseDown('horizontal'), a new instance of function is returned everytime and in order for eventListeners to be assigned and removed, the same instance of function needs to be passed. You could implement the above in the following manner

import * as React from 'react';

export default class ITestComponent extends React.Component { 

  public render() {
    return (
      <div>

        <div 
          onMouseDown={this.handleMouseDown.bind(this,'horizontal')}
          draggable={false}
          style={{ border: '1px solid blue', padding:20 }}
        >
          Horizontal Drag Test
        </div>

        <div 
          onMouseDown={this.handleMouseDown.bind(this,'vertical')}
          draggable={false}
          style={{ border: '1px solid green', padding:20 }}
        >
          Vertical Drag Test
        </div>

      </div>
    );
  }

  private handleMouseDown = (eType:string, e:any) => {
    console.log('Add Event Listeners (handleMouseDown)', eType)
    this._handleMouseMove = this.handleMouseMove.bind(this, eType);
    this._handleMouseUp = this.handleMouseUp.bind(this, eType);
    window.addEventListener('mousemove', this._handleMouseMove)
    window.addEventListener('mouseup', this._handleMouseUp)
  }

  private handleMouseMove =  (eType: string, e:MouseEvent) => {
    console.log(' - handleMouseMove', eType, e.clientY)
  };

  private handleMouseUp = (eType:string, e:MouseEvent) => {
    console.log('Remove Listeners (handleMouseUp)', eType)
    window.removeEventListener('mousemove', this._handleMouseMove)
    window.removeEventListener('mouseup', this._handleMouseUp);
  };

}
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • thanks Shubham - so there's no way to avoid using "bind" here really then? i.e. can't solve using arrow functions in this case? – Greg Dec 21 '18 at 09:25
  • You can avoid the bind in render by creating component out of the element but not in listeners. Refer https://stackoverflow.com/questions/45053622/how-to-avoid-bind-or-inline-arrow-functions-inside-render-method/45053753#45053753 – Shubham Khatri Dec 21 '18 at 09:55