Preact: Support for handleEvent DOM interface

Created on 1 Mar 2020  路  6Comments  路  Source: preactjs/preact

Reproduction

class Foo {
  click(e) {
    this.setState({ clicked: true })
  }

  handleEvent(e) {
    // nicety: `this` is the component
    this[e.type](e)
  }
  render() {
    return <button onClick={this} />
  }
}

Steps to reproduce

Click the button.

Expected Behavior

handleEvent is used and doesn't throw an error.

Actual Behavior

this.l[e.type](P.event ? P.event(e) : e) throws an error, as this.l[e.type] is this.

discussion feature request

Most helpful comment

That's interesting! First time I've heard of it. If you can't wait, you can patch that into Preact via an option hook:

import { options } from "preact";

let oldVNode = options.vnode;
options.vnode = vnode => {
  const { type, props } = vnode;

  // Only check DOM nodes
  if (typeof type === "string") {
    for (const name in props) {
      const value = props[name];
      if (value && typeof value.handleEvent === "function") {
        props[name] = value.handleEvent;
      }
    }
  }
  if (oldVNode) oldVNode(vnode);
};

All 6 comments

That's interesting! First time I've heard of it. If you can't wait, you can patch that into Preact via an option hook:

import { options } from "preact";

let oldVNode = options.vnode;
options.vnode = vnode => {
  const { type, props } = vnode;

  // Only check DOM nodes
  if (typeof type === "string") {
    for (const name in props) {
      const value = props[name];
      if (value && typeof value.handleEvent === "function") {
        props[name] = value.handleEvent;
      }
    }
  }
  if (oldVNode) oldVNode(vnode);
};

Thank you for the quick reply!
One note, wouldn't it be easier to check if the given event handler is this and then call it accordingly? Sadly, I don't understand Preact enough to help fix this - if you tell me how exactly are events added, or where, I could make prepare a PR.

Apart from that, I here is some imaginary code:
"before":
addEventListener(eventName, preactEventRouter, {opts})
"after":
addEventListener(eventName, eventFn === this ? this : preactEventRouter, {opts})

I hope this shows my point.

(More about this here: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38)

The trick here is that we currently use a "proxy" handle in order to avoid constantly removing and re-adding handlers when developers use inline functions in render methods. If we reimplement support for handleEvent on top of function listeners, it loses all of the performance advantages.

But! I think there might be a way for us to switch to internally using handleEvent...

Sounds reasonable and the but sounds interesting. Any help needed in exploring?

Definitely! I can throw a PR together that should at least show the rough outline of what we are proposing here, then we can go from there?

Sure, let's do this :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nopantsmonkey picture nopantsmonkey  路  3Comments

jescalan picture jescalan  路  3Comments

matthewmueller picture matthewmueller  路  3Comments

rajaraodv picture rajaraodv  路  3Comments

skaraman picture skaraman  路  3Comments