Xiaoyin Lin
Xiaoyin Lin

Reputation: 51

How to pass callback function to litelement from React?

I'm trying to use lit-element component in my React project, and I'd like to pass in the callback function to lit-element component from React but with no luck.

I've tried a couple of different ways, like change property type, and pass function in as a string, but none of them works.

lit-element component code:

import { LitElement, html } from "lit-element";

class MyButton extends LitElement {
  static get properties() {
    return {
      clickHandler: {
        type: String
      },
      bar: {
        type: String
      }
    };
  }

  render() {
    const foo = this.clickHandler; //value is undefined
    const bar = this.bar; //value is "it's bar"
    return html`
      <button @click=${this.clickHandler}>click me</button>
    `;
  }
}

customElements.define("my-button", MyButton);

react side code:

<my-button clickHandler={() => alert("clicked")} bar="it's bar" />

I put a break point in the render section of the component, and I can see the 'bar' value get passed in correctly, but the value of 'clickHandler' is undefined.

Does anyone have any idea on how to pass function from React to lit-element?

Thanks!

Upvotes: 5

Views: 5935

Answers (3)

windmaomao
windmaomao

Reputation: 7671

This question probably isn't just valid for react. It's quite general, how do I pass a handler from parent to child component, either it's a lit-element or html element.

According to the property doc, https://lit-element.polymer-project.org/guide/properties

<my-element 
  mystring="hello world"
  mynumber="5"
  mybool
  myobj='{"stuff":"hi"}'
  myarray='[1,2,3,4]'>
</my-element>

Doesn't seem that it supports (callback) function at the moment. So how does Element handle event from parent level ?

According to the event doc, https://lit-element.polymer-project.org/guide/events, you can dispatch any event to the dom tree, including your parent. Dom event system is much broader than React prop system.

class MyElement extends LitElement {
    ...
    let event = new CustomEvent('my-event', {
      detail: {
        message: 'Something important happened'
      }
    });
    this.dispatchEvent(event);
}

and then in either lit or non-lit context, use the following to handle the event,

const myElement = document.querySelector('my-element');
myElement.addEventListener('my-event', (e) => {console.log(e)});

This way you can allow children to fire implementation for parent, which is exactly the definition for callback.

Upvotes: 5

Dan Mindru
Dan Mindru

Reputation: 6104

What I found that works is adding a ref in the react component to the lit element, then literally setting the property on it.

So, for the following JSX:

<some-webcomponent ref={this.myRef}></some-webcomponent>

You can pass a property to ‘some-webcomponent’ in i.e. componentDidMount:

componentDidMount () {
  const element = this.myRef.current;
  element.someCallback = () => // ...
}

It’s not too pretty, but I wouldn’t consider it a hack either. Requires quite a lot of boilerplate though :/

Here’s a full React component for reference:

class MyComponent extends React.Component {   
  constructor(props) {     
    super(props);     
    this.myRef = React.createRef();   
  }   

  render() {     
    return <some-webcomponent ref={this.myRef}></some-webcomponent>;   
  } 

  componentDidMount() {
    const element = this.myRef.current;  
    element.someCallback = () => console.log(“call!”);
  }
}

Where the lit element is:

import { LitElement, html } from "lit-element";  

class SomeWebcomponent extends LitElement {
   static get properties() {    
     return {       
      someCallback: { type: Function }
     };
   }

   render() {     
     return html`       
       <button @click=${this.someCallback}>click me</button>     
     `;   
    } 
}  

customElements.define("some-webcomponent", SomeWebcomponent);

Upvotes: 1

John Teague
John Teague

Reputation: 9

Have a look at the menu button click function for the no redux pwa-starter-kit at https://github.com/Polymer/pwa-starter-kit/blob/template-no-redux/src/components/my-app.js. I believe that provides the example that may work for you.

Upvotes: 0

Related Questions