-
Notifications
You must be signed in to change notification settings - Fork 164
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
Improve support for reactive programming #3801
Comments
Thought on the implementation side on the above example for 1) Manually asking This could be something like having the
With this one could call 2) We should have a way of This could be achieved by having the implementation of
|
Furthermore I would like to see us implement build on top of this proposal something along these lines:
While the inlined templates in Java are awkward, it would allow languages like Kotlin and Scala build React-like inlined templates. This should probably be split to a separate ticket. |
That looks like TemplateRenderer in Grid. Maybe that could be made to work outside Grid. |
I see several different directions we could take when it comes to "reactive" support:
The thing that all of these basically do is that they eliminate the need for separately defining how to set initial values and how to react to incremental updates. Binder enhancementsThere have been numerous suggestions to somehow make This approach has two major limitations:
Classical reactive programmingThe basic idea is that you can connect any getter to any setter (optionally with a transformation, filter or asynchronous delimiter in between). When the value that the getter would return changes, the setter is automatically run with the new value. The main challenge here is that regular Java POJOs don't fire events when their setter is run (i.e. when the value returned by the getter changes). Beans would instead have to wrapped in proxies that make setters fire events, or alternatively data would be stored in a generic key-value store instead. Reactive with automatic listenersThis is small addition on top of the classical reactive approach. Instead of explicitly declaring which property a specific action depends on, the framework would automatically register which property values are read when running a specific action, and then automatically registering that action to be rerun when any of those properties are updated. React-style reactivenessThe React framework basically turns reactiveness upside down. Application logic only defines how to "initialize" (i.e. render) a component based on specific data, and then the framework takes care of comparing the newly initialized representation with the previously rendered version to figure out how to update the actual DOM. This approach has the benefit that it decouples the state of the application from the component tree, which in turn means that only the actual state needs to be stored in memory or serialized between requests. This approach might thus open the door for stateless or even paritally offline operation. |
Great overview @Legioth! I like what you're saying with decoupling the state from the component tree. I've been thinking about that for a while. Having Flow move from managing individual component states to managing application state would give us more freedom in where the logic resides and, like you said, could enable some interesting offline and stateless options in the future. |
+1 for the React-style approach. I do a lot of Clojure(Script) programming, and libraries like this (https://github.com/Day8/re-frame) really make for a cleaner, more comprehensible experience. |
I'm currently using The advantage of adopting core reactive Java APIs is that it comes free to have Vaadin components talk the same language with non-Vaadin ones, e.g. I have services providing a GraphQL API (via SPQR), so when an update happens both API subscribers via GraphQL subscriptions and UI users are pushed with the updates. I can share a sample of this if it may be of any interest. |
Hello everyone, some time ago, I was experiencing with combination of Vaadin and reactive programming and the result is and addon (https://github.com/dohnala/reactive-vaadin). It was just a proof of concept to see how this could work. There is also a demo with all features and code deployed at Heroku https://reactive-vaadin-demo.herokuapp.com/. Unfortunately, it is not completed, because lack of time. Documentation and support for Vaadin Flow is missing. It isn't published, too. The reason why I am writing here is that I am very interested in this combination and I would be very excited to get some feedback, critics, new ideas or even some people who would like to continue with this with me in any form. |
Introducing React-style or Meteor-style reactivity would most likely require quite significant changes, so I haven't really investigated those routes at this point. The other concepts can on the other hand be introduced cleanly on top of current concepts. Readonly bindingsOne very easy thing is to add readonly binding support for Readonly propertyThe item doesn't have a public setter, or alternatively the setter is never run while an item is being edited. The binding only needs to update when running This can be supported with any of the API suggestions from in #4980. Computed propertyThe computation needs to be re-run as the user makes changes through other bindings. In this case, the use of buffered mode (i.e. The generic case where multiple properties affect the computed result is doable already today using
Value subscriptionsTo better support reactive functionality in other contexts, any part of the framework that "publishes" a value could expose a generic API for creating one-way subscriptions to the value. This could be a fluent API where one could chain in various operations such as This is conceptually slightly similar to the One example of how this could be used is a situation where the choice in one dropdown changes the options in another dropdown. A basic example could be along these lines:
Another quite typical example is a checkbox that controls visibility of some other part of the UI. This could be supported by a shorthand that immediately accepts the published value.
Yet another relevant example is to automatically enable and disable a submit button based on whether a form is valid (assuming #4988 has been fixed).
|
There is one challenging aspect with the suggested
One thing that can be done to slightly simplify this particular case is if the return value of
That approach works quite smoothly when there's only two values to combine, but it's not pretty for multiple values. What would be needed in those cases are instead a helper that runs a callback whenever any dependency has changed, accepting one callback and a varargs array of
Taking this one step further, we could remove the need of passing the dependencies to The example could then be simplified to
This could be encapsulated in a
One final tweak could be to add a more discoverable shorthand for this pattern in association with setters that are typically expected to be used this this. This would increase discoverability over using a static method on an unrelated class.
|
I decided to take a quick look on what these ideas could mean in practice, and then I got slightly carried away. I ended up with a partial reference implementation and functional demo at https://github.com/Legioth/reactivevaadin and an explainer document for one of the most central concepts in https://vaadin.com/labs/viewmodel. You can see those as one design suggestion for this ticket. |
My latest thoughts revolve around using explicitly defined UI state as a way of also significantly reducing server-side session sizes to the point where all state could optionally be passed back and forth with each request and response so that a Flow application could even be deployed as FaaS. This concept is described in https://github.com/orgs/vaadin/discussions/3471 |
When I build a view, I want it to be a function of the current state.
Currently, Flow only supports data binding to
Field
s. This is restrictive and leads to a boilerplate code. I believe that improving support for reactive UI building would help increase developer productivity and happiness.Scenario:
I have a master-detail view of patient data. Selecting a patient should display or update a view of patient details based on a
Patient
object. I do not want to recreate the entire view on each change for performance reasons. The view contains a picture and both editable and non-editable information on the patient as well as buttons for saving or discarding changes. The save button is enabled/disabled based on form state and includes the patient's name, like "Save NNN's record", as a safeguard against updating the wrong patient's records.Current state
✔️
Binder
can be used to bind thePatient
object to the editable fields✖️I need to manually call
Button
'ssetEnabled()
from a listener onBinder
✖️I need to create and keep references to each
Span
used for non-editable info and callsetText()
on each every time thePatient
object changes✖️I need to keep a reference to the
Image
and manually set the image source every time thePatient
object changes✖️I need to keep a reference to the
Button
and manually set the text every time thePatient
object changesDesired outcome
I can bind any property of Components/Elements to functions of the state: in this case, my
Patient
object. Below are some non-working examples to show the idea. Something would need to observe the state object and trigger these functions to be re-evaluated.The same could probably also be achieved, perhaps easier for us, by making
Binder
more generic by allowing developers to bind any property on the bean to a function.The text was updated successfully, but these errors were encountered: