ref
callback returns a ReactComponent rather than a DOM Element #50
Description
When using a reactified version of a web component, I would expect that ref
would return me DOM Element directly, but instead it returns a ReactComponent.
import reactify from 'skatejs-react-integration';
const ReactComponent = reactify(skate('my-component', {}));
ReactDOM.render(<ReactComponent ref={el => /* el is ReactComponent instance */}/>, document.body);
This behaviour is documented in React.
What follows are some notes from my digging.
Why does reactify copy across my custom element prototype properties?
There's a few lines that appear to try to smooth the integration between the react component and the custom element, by copying across properties on the custom element prototype over to the react component.
However from eye balling the code, I would have thought any methods copied would use the wrong context if executed?
Why does ref
on <div/>
differ to <MyComponent />
?
It wasn't obvious to me why <div ref={} />
would behave differently to <MyComponent ref={} />
. To be honest I'd only ever used ref
on native DOM elements, so I'd never encountered the behaviour when using it on a react component.
I suspect the reason is that react components have no guarantee of always returning the same top-level element from render()
:
class MyComponent extends React.Component {
render() {
if (Math.random() > 0.5) {
return <div />;
} else {
return <p />;
}
}
)
Contrast this with a <div />
which is always going to be the same element.
So if ref
on a react component was to return a DOM element, it would introduce API complexity around handling the case when the top-level DOM element actually changes.
However for native DOM elements like <div />
it's safe for React to always return the DOM element directly, since the DOM element never changes. This is also true with custom elements, so in theory it would be safe for reactify
to ensure ref
returns the DOM element directly.
Can we use a ReactElement factory (with string type) rather than a React Component?
React already comes within out-of-the-box support for bridging between React and native elements via React.createFactory, so can't we just use that?
It has a few differences to reactify
:
- 👍
ref
returns a DOM element, rather than aReactComponent
instance. - 👎 Props are set as attributes rather than element properties (this would prevent callbacks from being passed through).
- 👎 Custom event handlers don't work.
Conclusion
After looking into this issue, the behaviour seems reasonable, but might benefit from some documentation in the README.