facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
227.66k stars 46.45k forks source link

touchmove doesn't fire on removed element #1355

Open sophiebits opened 10 years ago

sophiebits commented 10 years ago

If you have

{this.state.show &&
  <div onTouchStart={this.hideTheDiv} onTouchMove={...} />}

such that the onTouchStart handler removes the div (and maybe replaces it with another one in the same place, useful in certain draggable interactions), the onTouchMove handler doesn't fire because the events of a detached element no longer bubble to document. We should probably bind the touchmove handler when the element receives touchstart instead of delegating to document.

Sort of related to #1254.

cc @merbs @eater

jordwalke commented 10 years ago

Is this in the DOM spec? It's kind of strange.

sophiebits commented 10 years ago

Sorry, what's strange? Unlike mousemove, touchmove always fires on the element that received touchstart. In my limited testing, browsers happily send events to that removed element.

sophiebits commented 10 years ago

You can test http://jsbin.com/gocuhifa/1 on device or in Chrome/Firefox with touch events enabled (touch down on "monkey"; it'll disappear; move your finger and you'll get an alert).

sophiebits commented 10 years ago

Hmmmm maybe this isn't supposed to work:

https://docs.google.com/document/d/12-HPlSIF7-ISY8TQHtuQ3IqDi-isZVI0Yzv5zwl90VU/edit#heading=h.q2zqz8v0mja7

I sort of feel like it should still work in React just as well as it does in the browser though.

sophiebits commented 10 years ago

See also the W3C public-webevents list where I asked about this behavior.

sophiebits commented 10 years ago

This question is likely related: http://stackoverflow.com/q/24537000/49485.

sophiebits commented 10 years ago

https://plus.google.com/+RickByers/posts/GHwpqnAFATf also.

m-toyoda commented 9 years ago

+1

davidspiess commented 8 years ago

Same problem :/

92hackers commented 5 years ago

Optional solution: just hide the to removed element, such as css: position: absolute; z-index: -100;

nikitaeverywhere commented 4 years ago

touchmove and touchend events should always stick to the touchstart target. Check this answer for the correct implementation.

I believe in react this can be implemented manually with the user of ref now. However, as for React's onTouchStart/onTouchMove/onTouchEnd, I would expect them all to be bound to the onTouchStart target.

Nazeeh21 commented 3 years ago

I have been reading all the comments on this issue. So far, I understood that onTouchMove/onTouchEnd events should be bind to the onTouchStart event. If I got it correctly I would like to give it a try to fix this issue.

Skand17 commented 1 year ago

You are correct that when the div is removed from the DOM, its events will no longer bubble to the document and the onTouchMove handler will not fire. One solution to this problem is to bind the onTouchMove handler when the div receives a touchstart event, rather than delegating to the document.

Here is an example of how you might do this:

class MyComponent extends React.Component { constructor(props) { super(props); this.state = { show: true }; this.hideTheDiv = this.hideTheDiv.bind(this); this.onTouchStart = this.onTouchStart.bind(this); this.onTouchMove = this.onTouchMove.bind(this); } hideTheDiv() { this.setState({ show: false }); } onTouchStart(e) { e.currentTarget.addEventListener("touchmove", this.onTouchMove); } onTouchMove(e) { // handle touchmove event here } render() { return ( this.state.show && ( <div onTouchStart={this.onTouchStart} onTouchEnd={this.hideTheDiv} /> ) ); } }

In this example, when the div receives a touchstart event, the onTouchStart handler is called and it attaches the onTouchMove handler to the div element, so that it will fire when the user moves their finger. Additionally, it is important to remove the 'touchmove' event listener when the div is detached, to avoid memory leaks. This can be done by adding an onTouchEnd event that removes the 'touchmove' event listener.

It's worth noting that this approach may not be ideal if you need to handle touchmove events on multiple elements, because you will have to attach and remove event listeners on each element individually. In this case, it might be more appropriate to use a library such as Hammer.js that is specifically designed for handling touch and gesture events in a more efficient and flexible way.