Preact: ref callback not being triggered on wrapped elements

Created on 17 Feb 2018  路  4Comments  路  Source: preactjs/preact

Hey,

I've just switched to Preact and I've found some inconsistencies with the way the ref callback works. I have a draggable (DragSource) item from React DnD that I need the ref for, in order to use it for other purposes in my app. The below code gives me the ref in React, but the same does not happen in Preact (with Preact compat). The setRef function is simply never called in Preact. Any idea what might be happening here and how to work around it?

If I try to get the ref of the image, that works, so as a workaround I could add another div inside and get the ref there, but I don't want to add unnecessary containers. So a proper solution for this would be nice.

class MyComponent extends PureComponent {
  //...

  setRef = (ref) => {
    this.DOMNode = ref;
  }

  render () {
    const { connectDragSource, isDragging, item } = this.props;
    return connectDragSource(
      <div ref={this.setRef}>
        <img src={item.src} alt={item.name} />
      </div>
    )
  }
}
question

Most helpful comment

@cattermo you could do something like this in modern preact: https://codesandbox.io/s/cranky-tesla-1xz24

All 4 comments

This is because ReactDnD higher component wraps lower component's ref in its own in here, and extract original ref in here. Preact's vnode doesn't have ref property on itself, but in attributes. You can use Preact options vnode hook to modify vnode to suit this your usecase.

import { options } from 'preact'

options.vnode = function (vnode) {
    if (vnode.attributes && vnode.attributes.ref) {
        vnode.ref = vnode.attributes.ref
    }
    return vnode
}

This should fix your issue.

Yup! Here's another solution similar to @yaodingyd's lovely answer that patches all VNodes through their prototype:

import { h } from 'preact';

const VNode = h('a').constructor
Object.defineProperty(VNode.prototype, 'ref', {
  get() { return this.attributes.ref },
  set(v) { this.attributes.ref = v }
});

Sorry, I cannot get any of those fixes to work. Here is a codepen https://codepen.io/cattermo/pen/zYxyGEw

If any of you just have a minute to see whats wrong. Maybe the suggested solutions does not work with preact/compat?

@cattermo you could do something like this in modern preact: https://codesandbox.io/s/cranky-tesla-1xz24

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kossnocorp picture kossnocorp  路  3Comments

youngwind picture youngwind  路  3Comments

SabirAmeen picture SabirAmeen  路  3Comments

paulkatich picture paulkatich  路  3Comments

jescalan picture jescalan  路  3Comments