Replies: 1 comment 4 replies
-
Although client-side transactions would be a desirable feature
it seems that anywhere an atomic operation can be used in lieu of a client-side transaction, that would be preferable, similar to your recommendation for updating an array, such as
(not sure of the syntax). |
Beta Was this translation helpful? Give feedback.
4 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
The architectural concept of using "signals" for state management is establishing itself as a general approach throughout the frontend development ecosystem. There are some variations in syntax between
signal.value
and[getterFunction, setterFunction]
but the overall approach is the same with fine-grained reactivity and automatic tracking of dependencies. Specifically for Hilla, both React and Lit (as of version 3.0) are compatible with@preact/signals
which uses thesignal.value
syntax.Signals 101
As a simple example, a counter button using signals can be implemented like this in React
The power of signals is that a signal can just as well be shared between multiple independent components so that
counter
would not have to be scoped to a single component instance but instead be shared between multiple component instances. In that case, all visible components would be updated whenever any component changes the signal value.Compared to the default
useState
approach in React, the use of signals offers several benefits:computed()
andeffect()
are automatically updated whenever any dependency changes. This stands in contrast touseMemo
anduseEffect
that need explicitly defined dependency arrays.useContext
. As a related performance benefit, redundant invocations of the render function can also be avoided without any additional effort from the developer.<AutoGrid>
,<AutoForm>
and<AutoCrud>
functionality that is now designed specifically foruseState
and cannot easily be ported to Lit.Adopting signals as the primary approach for UI state management would mean that we use signals in tutorials and documentation examples in place of
useState
and that we design new functionality based on signals.Full stack shared signals
As a full-stack framework, Hilla can provide some unique additional benefits by making it easy to synchronize signal values between the browser and the server.
Multi-user signals
One way of reasoning about collaborative UIs is that some part of the UI state is shared between multiple users. A fundamental concept behind signals is that the value is updated from "somewhere else". There's nothing saying that this other place could be on the server or in some other user's browser. A shared signal could thus be returned from the server in a simliar way to how returning a
Flux
is used for setting up a subscription.Whereas the counter signal from
global.js
is shared within a browser tab, it could be changed to be shared between multiple tabs, browsers and users by acquiring it from the service instead.The one thing that changes with concurrently updated state is that you need to define changes in a granular way that are resistant to concurrent changes. In the counter example, concurrent button clicks will lead to two different users reading the same current value, e.g. 5, and concurrently write their incremented value to the signal. The end result would thus be two separate updates setting the value to 6 even though the actual number of clicks is then 7.
To deal with this, we need to submit a transactional update to the signal. This update will be retried if there's a conflict to make sure that the correct number of increments will eventually be applied (or use a customized signal type based on counting the number of increments instead of a general purpose value holder).
Correspondingly, adding an item to a shared array shouldn't be done using
signal.value = [...signal.value, newItem]
but instead with an atomic operation such assignal.insertLast(newItem)
. An atomic operation likeinsertLast
is also less code to write and more familiar for Java developers.CRUD signals
Sharing state between the server and the browser can also be beneficial for CRUD-like cases that persist data in a backend. Adding a value to a signal list corresponds to adding a new row to a database. This has the benefit that data operations on the client are expressed in the same way regardless whether they only update a local representation or also persist that change to a backend.
This requires a slightly more complex signal representation that supports pagination and filtering rather than always loading all the data. The power comes from combining client-updated signals for filtering and paging with a server-updated signal. The client only needs to do
employees.filterSignal.value = "asdf"
and this will trigger a request that will asynchronously update the value of aemployees
signal.employees
would also have achangesPending
signal that can be used to let the user know that data is being fetched.On the Java side, this CRUD signal could be represented in a similar way as the
CrudRepositoryService
class used with<AutoCrud>
.Beta Was this translation helpful? Give feedback.
All reactions