Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make it possible to get ReactAdapterComponent functionality with some other super class #19276

Open
jcgueriaud1 opened this issue Apr 29, 2024 · 6 comments

Comments

@jcgueriaud1
Copy link
Contributor

Describe your motivation

ReactAdapterComponent is an abstract implementation of an adapter for integrating with React components.

It extends from the Component class, as we can inherit from multiple classes in Java we can't use directly AbstractSinglePropertyField to bind a Field to a React component.

Describe the solution you'd like

If we transform the adapter to an interface with default methods it will allow to use directly AbstractSinglePropertyField.

An example of the implementation can be found here: https://github.com/jcgueriaud1/vaadin-react-field/blob/main/src/main/java/com/example/application/ui/react/prototype/IReactAdapterComponent.java

Describe alternatives you've considered

None. The idea is to keep the Java class similar if the frontend is implemented in React or Lit (or plain Javascript).
The interface is purely the copy of the abstract interface, unfortunately it's required to transform the protected method to default public.

@mshabarov
Copy link
Contributor

We can create a new interface and move there the functionality from ReactAdapterComponent, and then keep the ReactAdapterComponent abstract class as a shortcut for simple cases that implements this new interface and extends Component. What do you think?

Also, maybe a separate docs issue - we need an example of how to wrap a React component as a Flow field, e.g. to be able to use it with the Binder on a form.

@jcgueriaud1
Copy link
Contributor Author

As long as we can have an interface to avoid the boilerplate, I'm not against a abstract class in addition. I don't know if that will make things easier.

With ReactAdapterComponent class:

@JsModule("./react-component.tsx")
@Tag("react-component")
public class ReactMonthYearField
        extends ReactAdapterComponent {

With the interface:

@JsModule("./react-component.tsx")
@Tag("react-component")
public class ReactMonthYearField
        extends Component
        implements IReactAdapter {

Also, maybe a separate docs issue - we need an example of how to wrap a React component as a Flow field, e.g. to be able to use it with the Binder on a form.

Or a blog post, it depends a bit of what you want to implement (HasTooltip, HasLabel, HasHelper, HasValidation,...), that can be tough.
And that could be done for Lit or a webcomponent also :).

But at least in the repository I linked (https://github.com/jcgueriaud1/vaadin-react-field/), you have an example for both React and Lit.

@Legioth
Copy link
Member

Legioth commented May 3, 2024

I don't think an interface is the right option since interfaces define the public API of a class and you wouldn't want to make methods like setState part of the API that users of your component would see.

Instead, there might be an opportunity for a "connector" that you can use from your component. A simple example could thus look like this:

@Tag("some-tag")
@JsModule("./someModule")
public class MyComponent extends SomeOtherComponent {
  private final ReactComponentConnector connector = new ReactComponentConnector(this);
  public void setValue(String value) {
    connector.setState("value", value);
  }
}

@jcgueriaud1
Copy link
Contributor Author

I've just noticed that I'm not using the interface at all, since I'm using getElement().setProperty("invalid", invalid); and not setState("invalid",invalid);

I think the connector could handle the other case and leave everything protected. (I'm not sure if everything can be handled with properties)

@Legioth
Copy link
Member

Legioth commented May 3, 2024

The implementation of ReactAdapterComponent is basically just some helpers around Element::setPropertyJson, Element::getPropertyRaw and Element::addPropertyChangeListener. All of the actual magic is handled by Flow and/or the client-side base class for the custom element.

@knoobie
Copy link
Contributor

knoobie commented May 3, 2024

thumbs up for the connector idea This would allow the usage of AbstractSinglePropertyField and other important classes without cluttering the public interface.

@Legioth Legioth changed the title Transform ReactAdapterComponent to an interface Make it possible to get ReactAdapterComponent functionality with some other super class May 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: 🪵Product backlog
Development

No branches or pull requests

4 participants