Skip to content
This repository was archived by the owner on Sep 7, 2022. It is now read-only.
This repository was archived by the owner on Sep 7, 2022. It is now read-only.

ref callback returns a ReactComponent rather than a DOM Element #50

Closed
@bradleyayers

Description

@bradleyayers

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 a ReactComponent 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions