Compose state basics - devrath/ComposeAlchemy GitHub Wiki

π™²π™Ύπ™½πšƒπ™΄π™½πšƒπš‚
What is a state
Consider a primitive value as a state
Consider a state
Consider with a compose state
Consider with a compose state with side effect
Using remember with a state
Using remember & rememberSavable with state
Updating the state reference vs the content of the state

What is a state

  • State is something that changes over time. Thus a value that changes over time is called a state
  • This is not a state ---> const val TIME_OUT = 500
  • This is kinda state but not completely a state -------> var count = 0

Consider a primitive value as a state

  • Observe that on click even if I modify the primitive state variable, the Recomposition of the text is not triggered.
  • Simple primitive states cannot tell composables when they get updated.
  • The composable function needs to be recalled with a new value for recomposition to occur.
  • This is because no mechanism behind the primitive variables tells composables for initiating the recomposition.
  • This is the reason the state exists in composable.

Code

private var counterState = 0
@Composable
fun StatesWithPrimitiveDemoScreen(modifier: Modifier = Modifier) {
    Scaffold(
        modifier = Modifier.fillMaxSize()
    ) { padding ->
        Box(
            modifier = Modifier.fillMaxSize().padding(padding),
            contentAlignment = Alignment.Center
        ) {
            Button(
                onClick = {
                    counterState++
                }
            ) {
                Text(text = "Current Value -> $counterState")
            }
        }
    }
}

Consider a state

  • State is a value that can change over time also the appearance or the position of a composable --> Then it would be compose state.
  • Also we use remember along with a state because the remember caches the the value across the recompositions so that the value is not set again and again and when the value is altered the value cached is updated the process is repeated.
  • When you update a state and updating the state causes something else to be modified apart from the UI it is attached to is called side-effect

Code

@Composable
fun StatesWithComposeDemoScreen(modifier: Modifier = Modifier) {

    var counterState by remember { mutableIntStateOf(0) }

    Scaffold(
        modifier = Modifier.fillMaxSize()
    ) { padding ->
        Box(
            modifier = Modifier.fillMaxSize().padding(padding),
            contentAlignment = Alignment.Center
        ) {
            Button(
                onClick = {
                    counterState++
                }
            ) {
                Text(text = "Current Value -> $counterState")
            }
        }
    }

}

Consider with a compose state

code

@Composable
fun StatesWithComposeDemoScreen(modifier: Modifier = Modifier) {

    var counterState by remember { mutableIntStateOf(0) }

    Scaffold(
        modifier = Modifier.fillMaxSize()
    ) { padding ->
        Box(
            modifier = Modifier.fillMaxSize().padding(padding),
            contentAlignment = Alignment.Center
        ) {
            Button(
                onClick = {
                    counterState++
                }
            ) {
                Text(text = "Current Value -> $counterState")
            }
        }
    }

}

Consider with a compose state with side effect

  • Here notice the side-effect occurs and the count gets infinitely updated and gets appended continuously.
  • How this has happened because note the count mutable state must always be updated from normal lambda and not inside the compose scope

code

@Composable
fun StatesWithSideEffectDemoScreen(modifier: Modifier = Modifier) {

    var counterState by remember { mutableIntStateOf(0) }

    Scaffold(
        modifier = Modifier.fillMaxSize()
    ) { padding ->
        Box(
            modifier = Modifier.fillMaxSize().padding(padding),
            contentAlignment = Alignment.Center
        ) {
            Button(
                onClick = {
                    counterState++
                }
            ) {
                counterState++
                Text(text = "Current Value -> $counterState")
            }
        }
    }

}

Output

sideeffect.webm

Using remember with a state

  • The remember is a caching mechanism used to cache the variable that is kept the same across re-composition.
  • It is used because the variable is attained by a heavy computation and cached and does not need to perform the same operation every time on each re-composition.
  • When we use the state in combination with remember always when needed.
var counterState by remember { mutableIntStateOf(0) }

Using remember & rememberSavable with state

  • remember state ---------> Here the state is cached on recomposition but not on orientation change since entire composables are re-drawn.
var counterState by remember { mutableIntStateOf(0) }
  • rememberSavable state --> Here the state is cached on recomposition and the orientation change and also across process-death.
var counterState by rememberSavable { mutableIntStateOf(0) }

Updating the state reference vs the content of the state

  • If we just update the content of the state the composables that observe the state are not notified even if the contents of the state change.
  • If we change the reference of the state the recomposition is triggered.

code

@Composable
fun UpdatingContentOfStateDemoScreen(modifier: Modifier = Modifier) {

    var updateReference by remember { mutableStateOf(listOf("<-Item->")) }
    var updateContentOfReference by remember { mutableStateOf(mutableListOf<String>("<-Item->")) }

    Scaffold(
        modifier = Modifier.fillMaxSize()
    ) { padding ->
        Column(
            modifier = Modifier.fillMaxSize().padding(padding)
        ) {
            Column(
                modifier = Modifier.fillMaxSize().weight(1F).background(color = Color.Cyan)
            ) {

                Column(
                    modifier = Modifier.fillMaxSize(),
                    horizontalAlignment = Alignment.CenterHorizontally,
                    verticalArrangement = Arrangement.SpaceBetween
                ) {

                    Text(text = updateReference.toString())
                    
                    Button(onClick = {
                        updateReference = updateReference.plus("<-Item->")
                    }) {
                        Text(text = "Update references")
                    }
                }

            }
            Column(
                modifier = Modifier.fillMaxSize().weight(1F).background(color = Color.DarkGray)
            ) {

                Column(
                    modifier = Modifier.fillMaxSize(),
                    horizontalAlignment = Alignment.CenterHorizontally,
                    verticalArrangement = Arrangement.SpaceBetween
                ) {

                    Text(text = updateContentOfReference.toString())


                    Button(onClick = {
                        updateContentOfReference.add("<-Item->")
                    }) {
                        Text(text = "Update content of reference")
                    }
                }

            }
        }
    }

}

output

record.webm
⚠️ **GitHub.com Fallback** ⚠️