Rethinking User Actions to shape a better Unidirectional Data Flow | by Rygel Louv | Apr, 2022

Consumer Steps really should acquire an crucial area in UDF implementation.

Negligible image by Samantha Gades on Unsplash

Disclaimer: This short article was initially revealed as the 2nd component of this short article but immediately after contemplating about it, these two tales do not have much in popular and are completly impartial. So the title was transformed and content articles decoupled.

Unidirectional Data Flow is not a pattern we must introduce any more. This thought did enter the Android environment alongside with the MVI architecture sample. The MVI architecture has developed in popularity and even currently we can evidently see some of its concepts currently being greatly adopted even by Google. Due to the fact MVI was the initial architectural sample to counsel the concept of State management as we know it these days in the Android planet.
Unidirectional Information Move exposes the thought that the movement of info must go in a one direction. Indicating we go from an initial condition of the UI screen, the person interacts with the display, the user’s actions are processed and a new UI point out is created.

Image from having-rx-596f2f7637bb

In this post (browse it when you get the time) I argued that to have a cleaner UI code, a person really should make absolutely sure they stand for the UI as a solitary condition object that can be mutated if not, it may possibly close up in a mess.
Try to remember the purpose is to have a Watch that is passive, to have a dumb and stupid UI code which does typically displaying information and captures consumer enter. So undertaking some thing like this 👇 is undoubtedly much more most likely to add complexity and we should at some point stay away from:

Resource: Kaushik Gopal’s discuss on UDF

But alternatively, we want our UI Views to be far better structured and we want to have a distinct notion of how the details flows in the program.

Supply: Kaushik Gopal’s communicate on UDF

If you examine Google’s documentation, some crystal clear explanations and samples are presented about UDF but there is a single issue that bothers me about it, and that is the way user Steps are represented.

Imagine about it, they say UI point out need to be correctly represented. So we make details classes or sealed classes, objects to represent each and every attainable mutation of the UI. But when it will come to person actions most samples you will see will just let the UI contact the ViewModel’s features. I imagine Person Steps (what some may possibly phone UI Activities or Intents in MVI) should really also be modeled employing knowledge courses, objects, and sealed classes, and I will argue that it allows to provide a considerably cleaner code.

To start with of all, we implement UDF since we want a far more predictable code that can conveniently scale. In UDF, your ViewModel ought to expose only 1 object for condition observation and I assume furthermore, the See need to also connect with only a person purpose to present the user’s action. Essentially, One particular entry door and Just one exit doorway.

How do we do that?

To start with, we determine the actions

Then we can set up our ViewModel in a way that it consumes actions working with a Kotlin Channel:

So we even now have the capabilities but now, we can make them all non-public except for the processAction perform which is now the only community perform uncovered by the ViewModel.

What’s the gain of this?

As you can see, not considerably did actually adjust. But to explain how this can help the code to be cleaner, let’s consider an case in point in Jetpack Compose

In Jetpack Compose, we are encouraged to make our Composable stateless by moving Composable’s condition out to the caller. Which is what we call Point out Hoisting.
So mainly, go in the point out values to the Composable along with the functions that will be executed when a precise UI function takes place (That’s what I phone Steps in this publish).
The Android formal doc has a amazing case in point for it:

entertaining HelloScreen()
var identify by rememberSaveable mutableStateOf("")

HelloContent(identify = name, onNameChange = title = it )

enjoyment HelloContent(name: String, onNameChange: (String) -> Unit)
Column(modifier = Modifier.padding(16.dp))
textual content = "Hello, $title",
worth = name,
onValueChange = onNameChange,
label = Textual content("Name")

But, even nevertheless Condition Hoisting is certainly a pretty very good and crucial concept, I feel you might have by now come throughout the form of problem it can cause.
Let us say we have a dad or mum Composable that has several youngster Compasables and it requires UI occasion functions as parameters and passes them down to the distinctive boy or girl Composables. Right here is how it need to be accomplished pursuing Point out Hoisting:

As you can see, the MoviesScreenContent Composable has a large amount of parameters and this number will expand proportionally to the quantity of little one Composables. If you have Detekt in place, there is a likelihood that you get a LongParameterList mistake.
And which is the kind of trouble the Steps and ViewModel earlier established up, can assistance fix. What if we only passed a single parameter all over to dispatch an Action (UI Function) when it comes about? To do that we will have to set up the Motion technique on the UI side:

You will observe that we develop an actionChannel object that we will use to feed the steps to the ViewModel by calling viewModel.processAction(MoviesAction) and that is all we need to do.
Now with this, we can just go the actionChannel down to the boy or girl Composables instead of the lambda functions:

And how do we notify when the consumer performs an action? Straightforward, just place it in the channel.

With this refactoring, alternatively of passing ViewModel capabilities all-around as lambdas, you can now just pass the actionChannel around in its place and offer your actions when wanted. Thanks to the setup we did before, each individual time actionChannel.tySend(MoviesAction) is termed, viewModel.processAction(MoviesAction) is quickly termed which will result in the ideal perform in the ViewModel.
ViewModel.processAction() is our single entry doorway and ViewModel.state is our single exit doorway.

Works with the Check out process as well

Of system, you can use this refactoring in the see method also. You can choose advantage of FlowBings, and merge all your UI gatherings flows + the actionChannel flow, into a one movement.

How about one-shot events?

For single-shot activities like those made use of to show a Snackbar, the official Android doc has an example for it where by it is taken care of as component of the UI point out and they recommended preserving track of the activities fired with a clunky mechanism. I do not quite like this answer even though it respects the UDF pattern, it however feels much more like a workaround to me. I favor having a different SharedFlow event object that is applied for single-shot gatherings only. Or use the SideEffect components that appear with Compose. Up to you.

In this post, we have mentioned the requirement of modeling your person steps just like you do with your UI state and argued how this could support to somewhat boost your UI code and to established up a more crystal clear Unidirectional Knowledge Circulation.

Hold in mind that the concepts reviewed right here are incredibly opinionated, you may perhaps have a distinct point of see and if which is the case, I would appreciate to hear them in the feedback.
Thanks for studying.

Next Post

Grades for Cleveland selections in 2022 NFL Draft

The Cleveland Browns did not have a first spherical choose soon after the Deshaun Watson trade, and they then traded out of the second spherical. Cleveland utilised Working day 2 to shore up depth on defense and at receiver. This is the Browns’ picks, alternatives and grades for the 2022 […]
Grades for Cleveland selections in 2022 NFL Draft

You May Like