react-future icon indicating copy to clipboard operation
react-future copied to clipboard

Improved device input abstraction

Open iamdustan opened this issue 9 years ago • 5 comments

I would like to propose a greater abstraction from the top level composite events that the browser provides. This would allow developers building applications with react to avoid the complexity of composite events and heuristics that plague most cross-input applications.

https://github.com/facebook/react/issues/2061is the perfect example.

Depending on the UA, touchstart, touchmove, and touchend event details, and backwards-compatibility heuristics, the subsequent click event will often be delayed from the original user events by ~300ms. The fragmentation of UA implementations has only gotten worse in time (Chrome disabling it with certain heuristics like the <meta name="viewport" content="width=device-width"> with iOS8 introducing it’s own set of heuristics (https://github.com/ftlabs/fastclick/issues/262#issuecomment-47026051).

I believe that there is a great opportunity for React to take a step away from the browser event pipeline and do the sensible thing for the 95%. Begin with the click event, then move on to a sensible API for mouse, touch and pointer events.

To quote @petehunt

There is a lot of stuff you get for free when you build like the browser doesn’t exists and this is one thing that distinguishes React from Web Components and Polymer and that kind of thing …they’re getting closer and closer in with the browser, and we’re getting farther and farther from the browser. And I think that our technique is more sustainable in the long term.

iamdustan avatar Sep 23 '14 20:09 iamdustan

See facebook/react#1389 regarding pointer events, it seems they might not become standard.

While there is some downright horrible browser behavior for certain events (especially touch/mouse) that could hopefully be improved in quite sensible ways. Inventing our own APIs for input is an extremely complex subject, as is apparent by the uncertainty surrounding pointer events.

In my opinion, React cannot afford to get it (too) wrong, it's too big of a commitment... but it can afford browsers screwing it up because they're the ones carrying most of the burden. To me it's quite simple, if "we" can come up with API so fantastically great that it should undoubtedly be standard in React, it should instead be pitched to W3 to become a proper standard. If it doesn't pass that test then it very likely doesn't belong in React core either.

React so far is just an implementation of the DOM with some much appreciated improved cross-browser consistency, basically nothing else. I think it should (must even) stay that way. Anything the browsers doesn't support, shouldn't be supported by React core either IMHO.

Making the React event system "officially" pluggable is the possibly the correct solution in my opinion, it's a can of worms too (for reusable components) unless it's plugged and isolated at a component-level (not quite sure how that would work though). But at least it's up to the users to decide how "adventurous" they want to be.

Just as there have been countless frameworks before React competing for being "it", the same should apply to "event frameworks" IMHO. "Team React" understood what makes a fantastic app framework, it does not imply they will create a fantastic event framework, it's for others to compete for and hopefully someone will strike gold there too.

(The same applies to Flux, it's entirely separate from React, perhaps it'll eventually be crowned king of React models. But it could very well be that someone else has an even better idea.)

syranide avatar Sep 25 '14 15:09 syranide

@syranide thanks for your response. I’ve been thinking on this for a few days (and will be for a while).

I definitely get your concern. My ambition may be that I think React is uniquely poised to show browser engineers the superiority of PointerEvents (best case scenario) from a web developers perspective. In the minor interactions I’ve had on the Blink PointerEvents threads and meeting Rick Byers at EdgeConf a couple years ago, it seemed there was a chicken or the egg problem. How badly do web developers want this and is the cost of creating worth the benefit of having them.

Additionally, though, certain things can’t be undone from the web platform for historical reasons. The click event is so overloaded now that it is impossible to have it do the right thing because it has to do the safe thing.

What is the risk of React beginning to take more control of the composite events (such as click)?

My initial thinking is <div onclick={this.onClick} /> would not bind to the standard click event, but rather bind touchstart, pointerdown, mousedown, and keypress events.

touchstart: bind to touchmove and touchend events. If move delta is minor, fire onclick handler. pointerdown: bind to pointermove, pointerup events. If move delta is minor, fire onclick handler. mousedown: bind to mousemove and mouseup events. If move delta is minor, fire onclick handler. keypress: if key is spacebar, fire click event.

Would this already be a risky move? It would solve all the issues in https://github.com/facebook/react/issues/2061 and give non-mouse inputs first class support, while only taking a small step into the event agnostic game.

iamdustan avatar Oct 07 '14 02:10 iamdustan

I definitely get your concern. My ambition may be that I think React is uniquely poised to show browser engineers the superiority of PointerEvents (best case scenario) from a web developers perspective.

There are generic polyfills for PointerEvents available for those who want it. I stumbled upon some WebKit issues the other day that indicated that WebKit has decided against implementing PointerEvents. So it seems more and more likely that it won't become part of the standard.

Additionally, though, certain things can’t be undone from the web platform for historical reasons. The click event is so overloaded now that it is impossible to have it do the right thing because it has to do the safe thing .

What is the risk of React beginning to take more control of the composite events (such as click)?

I think you answered your own question, "can’t be undone from the web platform for historical reasons". It's so very easy for React to end up in that mess as well and suddenly React has it's own weirdly overloaded implementations that differs from the HTML standard and also has to be maintained for historical reasons.

I don't know for sure what the correct solution is and I'm sure all devs have different opinions on this. But I feel like React overloading the DOM is the wrong approach:

  1. We're going to get it wrong as well and React will be stuck in the mess we're trying to avoid
  2. We can't guarantee that all browsers will (always) behave the way we require (if our polyfills/overloads are non-trivial in nature).
  3. We might prevent other polyfill/overload behaviors from being possible (because we no longer expose the low-level ones required)

In my opinion, the best solution from a technical perspective is for React to expose the DOM as-is with some minor tweaks for normalizing behavior (discard invalid events, normalize event properties, etc). All fixes would then be layered on-top of this on a component-level (or descriptor-level even), React is no longer responsible for it and your codebase can even use newer better overloads in newer components without worrying about your older components.

If you imagine something like this, which should be possible in some sense today:

<BetterOnClick onClick={this.handleClick}>
  <div>
    <EvenBetterOnClick onClick={this.handleClick}>
      <div>
      </div>
    </EvenBetterOnClick>
  </div>
</BetterOnClick>

Surely there are better ways it could look, but if it works then that kind of implementation seems preferable to me. React has less responsibilties and users have more flexibility. I.e, it could look something like below, or something different entirely.

React.createClass({
  DOMEvents: {
    BetterClick: MyEventOverloads.BetterOnClick,
    EvenBetterClick: MyEventOverloads.EvenBetterOnClick
  },
  render: function() {
    return (
      <div onBetterClick={this.handleClick}>
        <div onEvenBetterClick={this.handleClick}>
        </div>
      </div>
    );
  }
});

syranide avatar Oct 07 '14 08:10 syranide

I would love something like this to be supported:

React.createClass({
  DOMEvents: {
    BetterClick: MyEventOverloads.BetterOnClick,
    EvenBetterClick: MyEventOverloads.EvenBetterOnClick
  },
  render: function() {
    return (
      <div onBetterClick={this.handleClick}>
        <div onEvenBetterClick={this.handleClick}>
        </div>
      </div>
    );
  }
});

This would also let us define custom events such as: onTap, onMouseStay etc. This is definitely the best use case, and it should only require some additional API.

For example, for onTap, we can already put onTouchStart, onTouchMove and onTouchEnd events and handle the logic manually. But it would be a HUGE win to be able to create the logic for onTap on one place and be able to just use onTap on the ReactElement.

nmn avatar Nov 25 '14 14:11 nmn

Agreed; came here looking for pretty much exactly the kind of solution @nmn's suggesting.

jareware avatar Feb 11 '15 10:02 jareware