Open jcgueriaud1 opened 3 months ago
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.
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.
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);
}
}
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)
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.
thumbs up for the connector idea This would allow the usage of AbstractSinglePropertyField
and other important classes without cluttering the public interface.
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 directlyAbstractSinglePropertyField
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.