Skip to content
DeveloperMemos

How to Pass a Delegated Mutable Variable to a Compose Function

Android Development, Jetpack Compose, MutableState, State Management1 min read

In Jetpack Compose, managing state is crucial for building responsive and dynamic UIs. However, when it comes to passing a delegated mutable variable (such as MutableState) to a Composable function, there are some considerations to keep in mind. Let's explore the problem and find a clean solution.

The Problem

Suppose we have a Composable function called Func() that initializes a MutableState variable:

1@Composable
2fun Func() {
3 val myMutableState by remember { mutableStateOf(true) }
4 Column {
5 AnotherFunc(mutableValue = myMutableState) // Error here
6 Text(if (myMutableState) "Stop" else "Start")
7 }
8}

In the above code, we're trying to pass myMutableState to another Composable function called AnotherFunc(). However, the direct approach using by won't compile because we can't pass it as an argument:

1@Composable
2fun AnotherFunc(mutableValue: MutableState<Boolean>) {
3 // ...
4}

The Solution

While the initial attempt seems intuitive, it's actually an anti-pattern. Jetpack Compose encourages adhering to the Single Source of Truth principle, which means avoiding passing mutable state as an argument. Instead, let's refactor our approach:

  1. Simplify the Parameter: Our AnotherFunc() should take a simple Boolean parameter instead of a MutableState:

    1@Composable
    2fun AnotherFunc(mutableValue: Boolean) {
    3 // ...
    4}
  2. Automatic Recomposition: When the value of myMutableState changes within Func(), Compose will automatically recompose the UI, including AnotherFunc().

  3. Assigning New Values: If you need to assign a new value to myMutableState within AnotherFunc(), you can use a callback approach. Define a lambda function that updates the value and pass it as an argument:

    1@Composable
    2fun AnotherFunc(mutableValue: Boolean, onMutableValueChange: (Boolean) -> Unit) {
    3 // ...
    4 onMutableValueChange(false) // Example: Assign a new value
    5}
  4. Usage:

    1@Composable
    2fun Func() {
    3 val myMutableState by remember { mutableStateOf(true) }
    4 Column {
    5 AnotherFunc(mutableValue = myMutableState) { newValue ->
    6 myMutableState = newValue // Update myMutableState
    7 }
    8 Text(if (myMutableState) "Stop" else "Start")
    9 }
    10}

By following this pattern, we maintain a clear separation of concerns, avoid mutable state as function parameters, and ensure proper UI recomposition. Remember that Jetpack Compose's reactive nature handles updates efficiently, making our code cleaner and more maintainable.