Sunday 21 August 2022

Jetpack Compose UI – Stateful, Stateless and State Hoisting

Jetpack Compose is a declarative approach of design and code, where as the typical imperative programming era moving to parallel universe of declarative programming.  Here on this process, it gives more impact on the UX and it rendering process, so it closely works on the single changes that would have to be repaint i.e. re-construct the UI as fully or partially whichever the use case demands.  So, the changes would be caught and works with UI States and these are works on the parameters of events and observers.  Here we going to see where and how the state works in our android app. 

Before we go into these details of Stateful and Stateless, we have to understand fewer things which connects the State and Composables. 

State on Composition & Re-Composition:  Compose is declarative one and through it will also calling the same composable with the new arguments on demand of changes, the arguments are the real representatives of this UI state. It would be anything the updates made on the state, the recomposition of UI will take place. 

For Example, things like TextField, Checkbox, and Option etc... As like as imperative programming (XML layout views) these widgets won’t automatically update while on selecting/toggling in compose. Here in a composable we have to explicitly tell the new state as value changed in order update. 

How the State Drive On: Composable functions can use the remember APIs to store an object in memory. A value computed by remember is stored in the Composition during initial composition, and the stored value is returned during recomposition. remember can be used to store both mutable and immutable objects, these objects are defined with mutableStateOf which is an observable type integrated with the compose runtime.

Now coming to our discussion point, how and what would be the Stateful and Stateless Compose?

Here is the screenshot of the use case and code snippet for both Stateful and Stateless compose will be as follows, 

Simple logic is in the initial screen click me is an action button it will keep increase by 1 on each click, on the regular interval of every 5 count and the ahead a step of 2, that text “I’m Visible between x to y” will be displayed and this keeps on continuing. (Refer this branch for the full Source code)

Stateful: Stateful is when composable uses remember to store an object i.e. create, holds and modifies its own State internally.  Stateful is useful when we don’t need to control the State of a composable.  However, the weakness of Stateful is that it tends to be less reusable and difficult to test.  

Here in the below code the state, ui and logic is completely packed into one single compose function. 

Stateless:  Stateless composable is a composable that doesn't hold any state, rather it only receive & hoist the state and this pattern is called State hoisting.  State hoisting in Compose is a pattern of moving state to a composable's caller to make a composable stateless.  Another thing by using this State Hoisting approach, we can easily mock the parent method by using Mockito and test our parent and child methods

Benefits of State Hoisting:
  • By Moving state instead of duplicating it, we’re ensuring there’s only one source of truth. This helps avoid bugs.
  • Only stateful composable will be able to modify their state. It’s completely internally encapsulated.
  • Hoisted states can be shared with multiple composable.
  • Only the callers to the stateless composable can decide to ignore or modify events before changing the state, easy to intercept
Here in the below code snippet, we have 3 compose functions (1 stateful and 2 stateless), maybe we can keep it as 2 compose, but I just wanted to make it intentionally 3 because want to separate the UI into two different stateless and passing state param and action as lambda param to the functions.

Statement from the official docs

“As we develop reusable Composables, we often want to expose both a Stateful and a Stateless version of the same composable. The Stateful version is convenient for callers that don’t care about the state, and the Stateless version is necessary for callers that need to control or hoist the State.”

Above Code Ref Gist: Sateful, StateHoisting